How to validate dependent parameters in PowerShell cmdlet - c#

What's the best way to do PowerShell cmdlet validation on dependent parameters? For example, in the sample cmdlet below I need to run validation that Low is greater than High but that doesn't seem to be possible with validation attributes.
[Cmdlet(VerbsCommon.Get, "FakeData")]
public class GetFakeData : PSCmdlet
{
[Parameter(Mandatory = true)]
[ValidateNotNullOrEmpty]
public int Low { get; set; }
[Parameter(Mandatory = true)]
[ValidateNotNullOrEmpty]
public int High { get; set; }
protected override void BeginProcessing()
{
if (Low >= High)
{
// Is there a better exception to throw here?
throw new CmdletInvocationException("Low must be less than High");
}
base.BeginProcessing();
}
protected override void OnProcessRecord()
{
// Do stuff...
}
}
Is there is a better way to do this? The main thing I don't like about the solution above is that I can't throw a ParameterBindingException like the validation attributes would do since it's an internal class. I could throw ArgumentException or PSArgumentException but those are really for Methods not cmdlets.

You need something like in the cmdlet get-random.
Because you can't use [validatescript()] attribute in a cmdlet 'cause it's valid only for powershell function/script at run-time you need to steal the idea from microsoft.powershell.utility\get-random:
The value check is done in the BeginProcessing() and use a customized error ThrowMinGreaterThanOrEqualMax
protected override void BeginProcessing()
{
using (GetRandomCommand.tracer.TraceMethod())
{
if (this.SetSeed.HasValue)
this.Generator = new Random(this.SetSeed.Value);
if (this.EffectiveParameterSet == GetRandomCommand.MyParameterSet.RandomNumber)
{
if (this.IsInt(this.Maximum) && this.IsInt(this.Minimum))
{
int minValue = this.ConvertToInt(this.Minimum, 0);
int maxValue = this.ConvertToInt(this.Maximum, int.MaxValue);
if (minValue >= maxValue)
this.ThrowMinGreaterThanOrEqualMax((object) minValue, (object) maxValue);
this.WriteObject((object) this.Generator.Next(minValue, maxValue));
}
else
{
double min = this.ConvertToDouble(this.Minimum, 0.0);
double max = this.ConvertToDouble(this.Maximum, double.MaxValue);
if (min >= max)
this.ThrowMinGreaterThanOrEqualMax((object) min, (object) max);
this.WriteObject((object) this.GetRandomDouble(min, max));
}
}
else
{
if (this.EffectiveParameterSet != GetRandomCommand.MyParameterSet.RandomListItem)
return;
this.chosenListItems = new List<object>();
this.numberOfProcessedListItems = 0;
if (this.Count != 0)
return;
this.Count = 1;
}
}
}
...
private void ThrowMinGreaterThanOrEqualMax(object min, object max)
{
if (min == null)
throw GetRandomCommand.tracer.NewArgumentNullException("min");
if (max == null)
throw GetRandomCommand.tracer.NewArgumentNullException("max");
string errorId = "MinGreaterThanOrEqualMax";
this.ThrowTerminatingError(new ErrorRecord((Exception) new ArgumentException(this.GetErrorDetails(errorId, min, max).Message), errorId, ErrorCategory.InvalidArgument, (object) null));
}
You can use a decompiler ( dotPeak ) to see the rest of the code to learn more on custom error for cmdlet

Related

When does a double become NaN?

I am trying to understand which circumstances can cause a double to become NaN.
For instance, 0/0 is nan. This is also stated in the official Documentation.
https://learn.microsoft.com/en-us/dotnet/api/system.double.nan?view=net-6.0
However, my debug code indicates that the division is not by 0:
public class StandardDeviation
{
public StandardDeviation()
{
Clear();
}
private double M { get; set; }
private double S { get; set; }
private uint Iteration { get; set; }
public double Value
{
get
{
return Math.Sqrt(S / (Iteration - 2));
}
}
public void AddValue(double value)
{
if (double.IsNaN(value))
{
throw new ArgumentException("value IS nan!");
}
double tmpM = M;
M += (value - tmpM) / Iteration;
S += (value - tmpM) * (value - M);
Iteration++;
if (double.IsNaN(M))
{
Console.WriteLine($"\nNAN EXCEPTION!!! divide by: {Iteration}");
Console.WriteLine($"\nNAN EXCEPTION!!! tmpM: {tmpM}");
throw new ArgumentException("m IS nan!");
}
}
public void Clear()
{
M = 0.0;
S = 0.0;
Iteration = 1;
}
}
console message:
NAN EXCEPTION!!! divide by: 3
NAN EXCEPTION!!! tmpM: ∞
The issue primairly seems to be prevalent in release configuration, which makes it hard to debug.
Whenever the exception is thrown, Iteration = 3.

How property actually manages to return Priority?

Here is the piece of code which represents so-called wrapper class PriorityQueue which contains three ordinary queues of different priority (High, Medium and Low) and tied with Enumeration Priority to which class Package () is connected via it's read-only property by the name Priority. And the Priority is being assigned via CreatePackage() method of PackageFactory class which creates objects (instances) of class Package (Package class have a constructor which requires to point it's _priority member in parentheses) using Random class and cast from int to Priority. This is the general background. Code is following below:
namespace PriorityQueue
{
enum Priority
{
High,
Medium,
Low
}
interface IPrioritizable
{
Priority Priority { get; }
}
class PriorityQueue<T> where T:IPrioritizable
{
private Queue<T> _queueHigh = new Queue<T>();
private Queue<T> _queueMedium = new Queue<T>();
private Queue<T> _queueLow = new Queue<T>();
public void Enqueue(T item)
{
switch (item.Priority)
{
case PriorityQueue.Priority.High:
_queueHigh.Enqueue(item);
break;
case PriorityQueue.Priority.Medium:
_queueMedium.Enqueue(item);
break;
case PriorityQueue.Priority.Low:
_queueLow.Enqueue(item);
break;
default:
throw new ArgumentOutOfRangeException(item.Priority.ToString(), "Bad priority in Priority queue. ");
}
}
public T Dequeue()
{
Queue<T> queueTop = TopQueue();
if (queueTop != null & queueTop.Count > 0)
{
return queueTop.Dequeue();
}
return default(T);
}
private Queue<T> TopQueue()
{
if (_queueHigh != null & _queueHigh.Count > 0) return _queueHigh;
if (_queueMedium != null & _queueMedium.Count > 0) return _queueMedium;
if (_queueLow != null & _queueLow.Count > 0) return _queueLow;
return _queueLow;
}
public int Count ()
{
return _queueHigh.Count + _queueMedium.Count + _queueLow.Count;
}
public bool IsEmpty()
{
return (_queueHigh.Count == 0) & (_queueMedium.Count == 0) & (_queueLow.Count == 0);
}
}
class Package:IPrioritizable
{
private Priority _priority;
public Package(Priority priority)
{
_priority = priority;
}
public Priority Priority => _priority;
}
class PackageFactory
{
Random _randgen = new Random();
public Package CreatePackage()
{
int numOfPriority = _randgen.Next(3);
return new Package((Priority)numOfPriority);
}
}
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("Creating PriorityQueue...");
PriorityQueue<Package> pq = new PriorityQueue<Package>();
Package pack;
PackageFactory fact = new PackageFactory();
Random rnd = new Random();
Console.WriteLine("\nNow we are going to create random number of 0-20 range as a number of packets to be created. ");
int numsToCreate = rnd.Next(20);
Console.WriteLine("\nAnd now we are creating {0} packages: ", numsToCreate);
for (int i = 0; i < numsToCreate; i++)
{
Console.Write("\tPackage {0} ", i);
pack = fact.CreatePackage();
Console.WriteLine("priority is: {0} ", pack.Priority);
pq.Enqueue(pack);
}
int total = pq.Count();
Console.WriteLine("\nTotal number of packages received is: {0}", total);
Console.WriteLine("\nNow we are going to create random number of 0-20 range as a number of packets to be removed. ");
int numsToRemove = rnd.Next(20);
Console.WriteLine("\nAnd now we are removing up to {0} packages: ", numsToRemove);
for (int i = 0; i < numsToRemove; i++)
{
pack = pq.Dequeue();
if(pack != null)
{
Console.WriteLine("Removed (shipped) package with priority: {0} ", pack.Priority);
}
}
Console.WriteLine("\nNumber of packages removed (shipped) is: {0}", total - pq.Count());
Console.WriteLine("\nPress any key to terminate program...");
Console.ReadKey();
}
}
}
Also there are customised Enqueue() and Dequeue() methods for PriorityQueue class. Actually what I don't understand is the Main() part of the program where we are using customised Dequeue() method to remove instances of Package class. How does the program learns of removed package via Priority property after customised Dequeue() method being used? Object was removed and how it can learn it Priority? Does it have to do something with reference types? Here is the part which I question:
for (int i = 0; i < numsToRemove; i++)
{
pack = pq.Dequeue();
if(pack != null)
{
Console.WriteLine("Removed (shipped) package with priority: {0} ", pack.Priority);
}
}

MinValue & MaxValue attribute for properties

Is it possible to make attribute which can limit minimum or maximum value of numbers.
Example:
[MinValue(1), MaxValue(50)]
public int Size { get; set; }
and when i do Size = -3; value of Size must be 1.
I searched in Google and can't find single example about this behavior, maybe because it is not possible to make?
I'm gonna use these attributes in property grid therefore having automatic validation can be handy.
Currently I workaround like this to limit minimum value:
private int size;
[DefaultValue(8)]
public int Size
{
get
{
return size;
}
set
{
size = Math.Max(value, 1);
}
}
So this acts like MinValue(1)
Although it is possible to create a custom attribute, attributes are just metadata for the member they annotate, and cannot change its behavior.
So, you won't get the behavior you want with a plain attribute. You need something to process the attributes in order to enact the desired behavior.
Take a look at TypeConverters for a possibility.
Yes, it is possible. Read about custom attributes at MSDN.
And by the way, there is already a solution you can use. It is the RangeAttribute which lets you specify the numeric range constraints for the value of a data field. Read more about it on MSDN.
You can elegantly solve this problem by using PostSharp by writing simple aspect, free version will be enough for this purpose:
[Serializable]
class RangeAttribute : LocationInterceptionAspect
{
private int min;
private int max;
public RangeAttribute(int min, int max)
{
this.min = min;
this.max = max;
}
public override void OnSetValue(LocationInterceptionArgs args)
{
int value = (int)args.Value;
if (value < min) value = min;
if (value > max) value = max;
args.SetNewValue(value);
}
}
and then exacly as you want:
class SomeClass
{
[Range(1, 50)]
public int Size { get; set; }
}
with normal usage:
var c = new SomeClass();
c.Size = -3;
Console.Output(c.Size);
will output 1.
create an extension
public static class Extensions
{
public static int FixedValue(this int value, int min, int max)
{
if (value >= min && value <= max)
return value;
else if (value > max)
return max;
else if (value < min)
return min;
else return 1;
}
}
And then:
private int size;
public int Size { get { return size.FixedValue(1, 50); }
set { size = value.FixedValue(1, 50); } }
Yes, it is possible with (already pointed) CustomAttributes, but mind, that you will loose the comfort of the auto-properties - because you need to apply resp. check the attribute restriction somewhere and in this case an appropriate place would be the getter of the property, so the interesting part of the problem is the application of the attributes. You can read how to access custom attributes in this MSDN article.
A possible solution for the MaxValue custom attribute can look like this:
// simple class for the example
public class DataHolder
{
private int a;
[MaxValue(10)]
public int A
{
get
{
var memberInfo = this.GetType().GetMember("A");
if (memberInfo.Length > 0)
{
// name of property could be retrieved via reflection
var mia = this.GetType().GetMember("A")[0];
var attributes = System.Attribute.GetCustomAttributes(mia);
if (attributes.Length > 0)
{
// TODO: iterate over all attributes and check attribute name
var maxValueAttribute = (MaxValue)attributes[0];
if (a > maxValueAttribute.Max) { a = maxValueAttribute.Max; }
}
}
return a;
}
set
{
a = value;
}
}
}
// max attribute
public class MaxValue : Attribute
{
public int Max;
public MaxValue(int max)
{
Max = max;
}
}
The sample usage:
var data = new DataHolder();
data.A = 12;
Console.WriteLine(data.A);
creates the output:
10
The code for the MinValue will look the same as for the MaxValue but the if condition will be less than instead of greater than.

How should I increment a number for a round robin threading scenario with least contention?

If many threads are calling GetNextNumber simultaneously with the following code, GetNextNumber will return 1 more times than any other numbers.
private class RoundRobbinNumber
{
private int _maxNumbers = 10;
private int _lastNumber;
private RoundRobbinNumber(int maxNumbers)
{
_maxNumbers = maxNumbers;
}
public int GetNextNumber()
{
int nextNumber = Interlocked.Increment(ref _lastNumber);
if (_lastNumber > _maxNumbers)
{
Interlocked.CompareExchange(ref _lastNumber, 1, _maxNumbers);
nextNumber = 1;
}
return nextNumber;
}
}
Is there a way to reset the _lastNumber back to one, and reliably return an incremented number for each thread calling GetNextNumber(), without having to use a lock?
Andrey's answer without conditional statements:
using System;
namespace Utils
{
public class RoundRobinCounter
{
private int _max;
private int _currentNumber = 0;
public RoundRobinCounter(int max)
{
_max = max;
}
public int GetNext()
{
uint nextNumber = unchecked((uint)System.Threading.Interlocked.Increment(ref _currentNumber));
int result = (int)(nextNumber % _max);
return result;
}
}
}
And here is a .net fiddle running this code.
The trick is to do the operation in a loop until it is successful. I provide a general template for this approach in my answer here.
public int GetNextNumber()
{
int initial, computed;
do
{
initial = _lastNumber;
computed = initial + 1;
computed = computed > _maxNumbers ? computed = 1 : computed;
}
while (Interlocked.CompareExchange(ref _lastNumber, computed, initial) != initial);
return computed;
}
Not sure if if helps anyone but this could be even simpler:
class RoundRobinNumber
{
private int _maxNumbers = 10;
private int _lastNumber = 0;
public RoundRobinNumber(int maxNumbers)
{
_maxNumbers = maxNumbers;
}
public int GetNextNumber()
{
int nextNumber = Interlocked.Increment(ref _lastNumber);
int result = nextNumber % _maxNumbers;
return result >= 0 ? result : -result;
}
}
Usually round-robin is used to select an item from a collection. Based on Alex's answer I made a RoundRobinCollection variant.
public class RoundRobinCollection<T>
{
private readonly ReadOnlyCollection<T> _collection;
private int _currentNumber = -1;
public RoundRobinCollection(IEnumerable<T> enumerable)
{
_collection = new List<T>(enumerable).AsReadOnly();
if (!_collection.Any())
{
throw new InvalidOperationException("Cannot use empty collection for RoundRobinCollection.");
}
}
public T GetNext()
{
var index = GetNextIndex();
return _collection[index];
}
private int GetNextIndex()
{
// This increments the currentNumber in a Thread-safe way, and deals with exceeding int.MaxValue properly
var nextNumber = unchecked((uint)Interlocked.Increment(ref _currentNumber));
return (int)(nextNumber % _collection.Count);
}
}
Usage example:
public class SomeClient
{
private readonly RoundRobinCollection<ServerConfig> _serverConfigs;
public SomeClient(List<ServerConfig> serverConfigs)
{
_serverConfigs = new RoundRobinCollection<ServerConfig>(serverConfigs);
}
public void DoSomething(){
var serverConfig = _serverConfigs.GetNext();
// Do something with current serverConfig
}
}

Elegant way to validate values

I have a class with many fields which represents different physical values.
class Tunnel
{
private double _length;
private double _crossSectionArea;
private double _airDensity;
//...
Each field is exposed using read/write property. I need to check on setter that the value is correct and generate exception otherwise. All validations are similar:
public double Length
{
get { return _length; }
set
{
if (value <= 0) throw new ArgumentOutOfRangeException("value",
"Length must be positive value.");
_length = value;
}
}
public double CrossSectionArea
{
get { return _crossSectionArea; }
set
{
if (value <= 0) throw new ArgumentOutOfRangeException("value",
"Cross-section area must be positive value.");
_crossSectionArea = value;
}
}
public double AirDensity
{
get { return _airDensity; }
set
{
if (value < 0) throw new ArgumentOutOfRangeException("value",
"Air density can't be negative value.");
_airDensity = value;
}
}
//...
Is there any elegant and flexible way to accomplish such validation?
Assuming you want this sort of behaviour, you might consider some helper methods, e.g.
public static double ValidatePositive(double input, string name)
{
if (input <= 0)
{
throw new ArgumentOutOfRangeException(name + " must be positive");
}
return input;
}
public static double ValidateNonNegative(double input, string name)
{
if (input < 0)
{
throw new ArgumentOutOfRangeException(name + " must not be negative");
}
return input;
}
Then you can write:
public double AirDensity
{
get { return _airDensity; }
set
{
_airDensity = ValidationHelpers.ValidateNonNegative(value,
"Air density");
}
}
If you need this for various types, you could even make it generic:
public static T ValidateNonNegative(T input, string name)
where T : IComparable<T>
{
if (input.CompareTo(default(T)) < 0)
{
throw new ArgumentOutOfRangeException(name + " must not be negative");
}
return input;
}
Note that none of this is terribly i18n-friendly...
All depends what technology you are using - if you're under MVC you can use Attributes, like this;
http://msdn.microsoft.com/en-us/library/ee256141(v=vs.98).aspx
Here's my version, it's a bit cleaner than Jon's version in some respects:
interface IValidator <T>
{
bool Validate (T value);
}
class IntValidator : IValidator <int>
{
public bool Validate (int value)
{
return value > 10 && value < 15;
}
}
class Int2Validator : IValidator<int>
{
public bool Validate (int value)
{
return value > 100 && value < 150;
}
}
struct Property<T, P> where P : IValidator<T>, new ()
{
public T Value
{
set
{
if (m_validator.Validate (value))
{
m_value = value;
}
else
{
Console.WriteLine ("Error validating: '" + value + "' is out of range.");
}
}
get { return m_value; }
}
T m_value;
static IValidator<T> m_validator=new P();
}
class Program
{
static void Main (string [] args)
{
Program
p = new Program ();
p.m_p1.Value = 9;
p.m_p1.Value = 12;
p.m_p1.Value = 25;
p.m_p2.Value = 90;
p.m_p2.Value = 120;
p.m_p2.Value = 250;
}
Property<int, IntValidator>
m_p1;
Property<int, Int2Validator>
m_p2;
}
Try to use such a method:
public void FailOrProceed(Func<bool> validationFunction, Action proceedFunction, string errorMessage)
{
// !!! check for nulls, etc
if (!validationFunction())
{
throw new ArgumentOutOfRangeException(errorMessage);
}
proceedFunction();
}
Yes, by creating your own validation attributes.
Read this article: Business Object Validation Using Attributes in C#
I will have the decency of NOT copying it here :)
Using the Validator function I mentioned in my comment above, I'd do something like this (untested code):
void textBox_Changed(object sender, EventArgs e) {
submitButton.Enabled = validator();
}
bool validator() {
const string NON_POSITIVE = "Value must be greater than Zero";
bool result = false;
string controlName = "Length";
try {
_length = Convert.ToDouble(txtLength.Text);
if (_length <= 0) throw new Exception(NON_POSITIVE);
controlName = "Cross Section Area";
_crossSectionArea = Convert.ToDouble(txtCrossSectionArea.Text);
if (_crossSectionArea <= 0) throw new Exception(NON_POSITIVE);
controlName = "Air Density";
_airDensity = Convert.ToDouble(txtAirDensity.Text);
if (_airDensity <= 0) throw new Exception(NON_POSITIVE);
result = true; // only do this step last
} catch (Exception err) {
MessageBox.Show(controlName + " Error: " + err.Message, "Input Error");
}
return result;
}
John Skeet probably has a better way, but this works. :)
You can achieve this using classes from System.ComponentModel.DataAnnotations
class Tunnel
{
[Range(0, double.MaxValue, ErrorMessage = "Length must be positive value.")]
public double Length { get; set; }
}
Validation:
var tunnel = new Tunnel { Length = 0 };
var context = new ValidationContext(tunnel, null, null);
Validator.ValidateObject(tunnel, context, true);
Also you can implement your own validation attributes overriding ValidationAttribute class

Categories