I'm trying to validate this class: min >= max. I realized using generics I can't use the comparators.
This is my generic class.
public class Range<T>
{
public T MinValue { get; set; }
public T MaxValue { get; set; }
public Range() { }
public Range(T min, T max)
{
this.MinValue = min;
this.MaxValue = max;
}
public override bool Equals(object obj)
{
if (obj == null) return false;
var other = obj as Range<T>;
return this.MinValue.Equals(other.MinValue) &&
this.MaxValue.Equals(other.MaxValue);
}
public override string ToString()
{
return string.Format("{0},{1}", this.MinValue, this.MaxValue);
}
}
T datatype can be only numbers, is there a way to accept just numbers and accept the <=?
No, you can't constrain generics to numbers, but you can constrain T to IComparable<T> and then use CompareTo()
public class Range<T> where T : IComparable<T>
{
....
}
Then you can say:
if (min.CompareTo(max) >= 0)...
And throw a validation exception or whatever validation you'd like. You can use the same thing to make sure value is >= min and <= max.
if (value.CompareTo(min) >= 0 && value.CompareTo(max) <= 0)...
public class Range<T> where T : IComparable<T>
{
...
public bool Check(T value)
{
return value.CompareTo(min) >= 0 && value.CompareTo(max) <= 0;
}
}
If you range between 0 and 10, and want 0, 10 to fail (exclude min and max) - simply replace ">=" with ">" and "<=" with "<".
I would also recommend changing in the Equals override from:
return this.MinValue.Equals(other.MinValue) &&
this.MaxValue.Equals(other.MaxValue);
to this:
return this.MinValue.CompareTo(other.MinValue) == 0 &&
this.MaxValue.CompareTo(other.MaxValue) == 0;
Related
Error:
Operator '<=' cannot be applied to operands of type string and int.
In my case 'details[0].max' Consists of value 0.0 like this.
if (!string.IsNullOrEmpty(details[0].customsalary) && (details[0].max) <= 0 && (details[0].max) <= 0)
{
_jobdetailsmodel.Salary = details[0].customsalary;
}
if value of details[0].max is 0.0 and details[0].min is 0.0 then condition should become true.
It seems that 'details[0].max' is string type So please cast it it to Double as:
Convert.ToDouble(details[0].max)
Explicitly cast details[0].max to a number, something like
if (!string.IsNullOrEmpty(details[0].customsalary) && decimal.Parse(details[0].max) <= 0)
depending on the expected type of details[0].max.
The issue is down to your .max variables likely being strings. The below code should be enough to get your if statement to work by converting them to integers in the if statement.
I would recommend however potentially reviewing your code and maybe converting these variables to integers in order to avoid having to convert their values at all.
if (!string.IsNullOrEmpty(details[0].customsalary) && Convert.ToInt32(details[0].max) <= 0 && Convert.ToInt32(details[0].max) <= 0)
{
_jobdetailsmodel.Salary = details[0].customsalary;
}
Details[0].max is a string, therefor you need to convert to int, the below code allows for incorrectly formatted strings, where int.Parse will throw an exception if the string is invalid:
if (!string.IsNullOrEmpty(details[0].customsalary) &&
int.TryParse(details[0].max, out var max) &&
int.TryParse(details[0].min, out var min) &&
max <= 0 && min <= 0)
{
_jobdetailsmodel.Salary = details[0].customsalary;
}
details is array of what ? And max, it's an int, a double, something else ?
There is an example of a Detail class:
public class Detail1
{
public string CustomSalary { get; set; }
public int Max { get; set; }
public decimal Max2 { get; set; }
}
It could be :
public class Detail2
{
public string CustomSalary { get; set; }
public string Max { get; set; }
public string Max2 { get; set; }
}
Please be more specific
using Detail2 class, you can use Parse extension methods (numeric types has this extension method):
if(!string.IsNullOrWhiteSpace(detail[0].CustomSalary)
&& int.Parse(details[0].Max) <= 0
&& decimal.Parse(details[0].Max2 <= 0.0m))
{
//....
}
You can use System.Convert class too:
if(!string.IsNullOrWhiteSpace(detail[0].CustomSalary)
&& Convert.ToInt(details[0].Max) <= 0
&& Convert.ToDecimal(details[0].Max2 <= 0.0m))
{
//....
}
And if you're not sure there's any value (in details[0]), you can add ? after details[0] and/or use TryParse extension method:
int.TryParse(details[0].Max, out int max);
decimal.TryParse(details[0]?.Max2, out decimal max2);
if(!string.IsNullOrWhiteSpace(detail[0]?.CustomSalary)
&& max <= 0
&& max2 <= 0.0m)
{
//....
}
I this case, you don't know the type of Max and Max2 properties. (it can be a simple object)
I am new to C# and trying to implement a numeric limit class as :
internal class NumericLimit<TValue> where TValue : IComparable
{
public NumericLimit(TValue min, TValue max)
{
this.Max = max;
this.Min = min;
}
internal TValue Max { get; }
internal TValue Min { get; }
internal bool WithinBounds(TValue min, TValue max)
{
if (min.CompareTo(this.Min) <= 0 &&
max.CompareTo(this.Max) >= 0)
return true;
return false;
}
internal bool LessThan(TValue value)
{
return (value.CompareTo(this.Max) > 0);
}
internal bool GreaterThan(TValue value)
{
return (value.CompareTo(this.Min) < 0);
}
internal bool Contains(TValue value)
{
if (value.CompareTo(this.Max) == 0 ||
value.CompareTo(this.Min) == 0)
return true;
return (value.CompareTo(this.Min) > 0) &&
(value.CompareTo(this.Max) < 0);
}
internal bool Defined()
{
return true;
}
}
The problem is how to implement Defined() function. I want the NumericLimit to be invalid/undefined when both Min and Max values are -1.
Like, for NumericLimit<long> the limit is undefined when both Min and Max are -1L.
And for NumericLimit<int> the limit is undefined when both Min and Max are -1.
How to implement 'Defined' in a way that correctly represents negative one for TValue type ?
What if after some time you decide to use NumericLimit<double> or some other type for T that will not accept value of -1? I suggest using special IsDefined flag and adding static method for constructing undefined limit:
internal class NumericLimit<TValue> where TValue : IComparable
{
internal bool IsDefined { get; }
public NumericLimit(TValue min, TValue max)
{
this.Max = max;
this.Min = min;
IsDefined = true;
}
private NumericLimit()
{
IsDefined = false;
}
public static NumericLimit<TValue> Undefined()
{
return new NumericLimit<TValue>();
}
// ...
}
My problem is that I always want to order a collection of objects in a certain fashion.
For example:
class foo{
public string name {get;set;}
public DateTime date {get;set;}
public int counter {get;set;}
}
...
IEnumerable<foo> dosomething(foo[] bar){
return bar.OrderBy(a=>a.name).ThenBy(a=>a.date).ThenBy(a=>a.counter);
}
The issue I have is its quite longwinded tacking-on the sort order all the time. A neat solution appears to just create a class that implements IComparer<foo>, meaning I can do:
IEnumerable<foo> dosomething(foo[] bar){
return bar.OrderBy(a=>a, new fooIComparer())
}
.
The problem is, the order method this implements is as follows
...
public int Compare(foo x, foo y){ }
Meaning it compares on a very granular basis.
The currently implementation (which will probably work, although im writing pseudocode)
public int Compare(foo x, foo y){
if (x==y)
return 0;
var order = new []{x,y}.OrderBy(a=>a.name).ThenBy(a=>a.date).ThenBy(a=>a.counter);
return (order[0] == x) ? -1 : -1;//if x is first in array it is less than y, else it is greater
}
This is not exactly efficient, can another offer a neater solution? Ideally without a Compare(x,y) method altogether?
Option 1 - The Comparer
As you're ordering by multiple conditions, you'll to check them individually within each case; for example, if x.name and y.name are equal, then you would check x.date and y.date, and so on.
public class FooComparer : IComparer<Foo>
{
public int Compare(Foo x, Foo y)
{
// nasty null checks!
if (x == null || y == null)
{
return x == y ? 0
: x == null ? -1
: 1;
}
// if the names are different, compare by name
if (!string.Equals(x.Name, y.Name))
{
return string.Compare(x.Name, y.Name);
}
// if the dates are different, compare by date
if (!DateTime.Equals(x.Date, y.Date))
{
return DateTime.Compare(x.Date, y.Date);
}
// finally compare by the counter
return x.Counter.CompareTo(y.Counter);
}
}
Option 2 - The extension method
An alternative, not so appealing approach, could be an extension method. Sadly as the TKey for each ThenBy can be different, we lose the power of generics, but can safely replace it with the type object in this case.
public static IOrderedEnumerable<T> OrderByThen<T>(this IEnumerable<T> source, Func<T, object> selector, params Func<T, object>[] thenBySelectors)
{
IOrderedEnumerable<T> ordered = source.OrderBy(selector);
foreach (Func<T, object> thenBy in thenBySelectors)
{
ordered = ordered.ThenBy(thenBy);
}
return ordered;
}
You have to implement IComparable<foo> and compare all properties:
class foo: IComparable<foo>, IComparer<foo>
{
public string name { get; set; }
public DateTime date { get; set; }
public int counter { get; set; }
public int Compare(foo x, foo y)
{
if (x == null || y == null) return int.MinValue;
if (x.name != y.name)
return StringComparer.CurrentCulture.Compare(x.name, y.name);
else if (x.date != y.date)
return x.date.CompareTo(y.date);
else if (x.counter != y.counter)
return x.counter.CompareTo(y.counter);
else
return 0;
}
public int CompareTo(foo other)
{
return Compare(this, other);
}
}
Then you can use OrderBy in this way:
var ordered = foos.OrderBy(f => f).ToList();
what's wrong with an extension method?
Why wont you simply compare your values:
int Compare(foo x, foo y)
{
if (x== null && y == null)
return 0;
else if (x == null)
return -1;
else if (y == null)
return 1;
var nameComparision = string.Compare(x.name,y.name);
if (nameComparision != 0)
return nameComparision;
var dateComparision = x.date.CompareTo(y.date);
if (dateComparision != 0)
return dateComparision;
var counterComparision = x.counter.CompareTo(y.counter);
return counterComparision;
}
I am coding a generic Binary Tree in C#.
In one portion of my application I need to sort in order of distance.
from A to C and B to C.
something like this:
if ((A->C) == (B->C))
return 0;
else if((A->C) < (B->C))
return -1;
else
return 1;
But the problem is, I can only compare between 2 objects... and I need some kind of comparator.
Creating a class like "distance between start and end" is a correct solution? I Think it creates too much garbage.
Any solution?
Thanks ;-)
edit:
public AvlNode<T> _left, _right;
public Stack<T> _obj;
(...)
public AvlNode<T> Insert(T obj, IComparer<T> iComparer)
{
if (iComparer.Compare(obj, _obj.Peek()) > 0)
{
_right = (_right != null) ? _right.Insert(obj, iComparer) : new AvlNode<T>(obj);
return Balance();
}
else if (iComparer.Compare(obj, _obj.Peek()) < 0)
{
_left = (_left != null) ? _left.Insert(obj, iComparer) : new AvlNode<T>(obj);
return Balance();
}
else
{
_obj.Push(obj); // distance already exists but object may be different, that's why I use a stack...
return this;
}
}
I dont have a working IComparer...
Edit:
Problem Solved, now I have a working IComparer!
public class ObjectDistanceComparer : IComparer<EraObject>
{
Vector3 _position;
public ObjectDistanceComparer(Vector3 position)
{
_position = position;
}
int IComparer<EraObject>.Compare(EraObject obj1, EraObject obj2)
{
float d1 = (_position - obj1._position).LengthSquared();
float d2 = (_position - obj2._position).LengthSquared();
return (d1 == d2)? 0 : (d1 < d2)? -1 : 1;
}
}
Thanks ;-)
You could add extra property to your Node class:
public class Node : IComparable
{
Node Parent{get;set;}
Node LChild {get;set;}
Node RChild {get;set;}
Node C {get;set;}
public int CompareTo(object o)
{
// Now you passed C in your object, do stuff ...
}
}
public class Distance
{
int Source {get;set;}
int Destination{get;set;}
int Value{
get{ return Math.Abs(Destination - Source);}
}
}
I have a need to restrict certain numbers to valid ranges in my application. I created delegates to handle this. I don't know if this is the right way to do it; I'm running into something that feels wrong.
public delegate int RestrictInteger(int minimum, int maximum, int value);
public delegate decimal RestrictDecimal(decimal minumum, decimal maximum, decimal value);
class GameMath
{
public static int RestrictNumber(int minimum, int maximum, int value)
{
if (value < minimum) { value = minimum; }
else if (value > maximum) { value = maximum; }
return value;
}
public static decimal RestrictNumber(decimal minimum, decimal maximum, decimal value)
{
if (value < minimum) { value = minimum; }
else if (value > maximum) { value = maximum; }
return value;
}
}
public class SomeClass
{
public int aValue { get; set; }
public void SetValue(int value)
{
RestrictInteger doRestrict = new RestrictInteger(GameMath.RestrictNumber);
this.aValue = doRestrict(0, 100, value);
}
}
On one hand, it seems like if I added more signatures, then I'd want to be able to do different things with them (say, conversions, or rounding, etc.). On the other hand, between these two signatures, the code is precisely the same. Is that okay, or is there some way to write one operation which applies to both these cases, even if other cases might use different operations?
Yes, you can do this with generics - although not with < and >. You should use the fact that these types implement IComparable<T> for themselves:
public static T RestrictNumber<T>(T min, T max, T value) where T : IComparable<T>
{
return value.CompareTo(min) < 0 ? min
: value.CompareTo(max) > 0 ? max
: value;
}
(You could still use your original code here - I rather like this sort of use of the conditional operator though; it satisfies my growing functional tendencies.)
(I'm late to the party, but wanted to take a shot at it)
I think this syntax reads well:
Restrict.Value(x).ToBetween(0, 100)
You can do it by defining a restriction interface:
public interface IRestrictable<T> where T : IComparable<T>
{
T ToBetween(T minimum, T maximum);
}
Then, define a static class which provides the implementation and a method which infers the type:
public static class Restrict
{
public static IRestrictable<T> Value<T>(T value) where T : IComparable<T>
{
return new Restricter<T>(value);
}
private sealed class Restricter<T> : IRestrictable<T> where T : IComparable<T>
{
private readonly T _value;
internal Restricter(T value)
{
_value = value;
}
public T ToBetween(T minimum, T maximum)
{
// Yoink from Jon Skeet
return _value.CompareTo(minimum) < 0
? minimum
: _value.CompareTo(maximum) > 0 ? maximum : value;
}
}
}
Depending on how you will use these numbers, there may be instances when a type with an implicit operator will be useful.
It allows you to use common comparison and unary operators, such as < <= > >= + -, and to mix usage between the T type and the RestrictedNumber type, so, for example, you can pass a RestrictedNumber to any method that expects a double, all the while still holding on to the initial value that may have been out of range.
You never have to call any methods to perform restriction or casting -- everything can be set upon declaration.
See the second class below for usage examples and notes.
Having misplaced Occam's Razor:
public class RestrictedNumber<T> : IEquatable<RestrictedNumber<T>>, IComparable<RestrictedNumber<T>>
where T: IEquatable<T>,IComparable<T>
{
T min;
T max;
readonly T value;
public RestrictedNumber(T min, T max, T value)
{
this.min = min;
this.max = max;
this.value = value;
}
public T UnrestrictedValue
{
get{ return value; }
}
public static implicit operator T(RestrictedNumber<T> n)
{
return get_restricted_value(n);
}
public static implicit operator RestrictedNumber<T>(T value)
{
return new RestrictedNumber<T>(value, value, value);
}
static T get_restricted_value(RestrictedNumber<T> n)
{
// another yoink from Jon Skeet
return n.value.CompareTo(n.min) < 0 ? n.min
: n.value.CompareTo(n.max) > 0 ? n.max
: n.value;
}
T restricted_value
{
get { return get_restricted_value(value); }
}
public T Min // optional to expose this
{
get { return this.min; }
set { this.min = value; } // optional to provide a setter
}
public T Max // optional to expose this
{
get { return this.max; }
set { this.max = value; } // optional to provide a setter
}
public bool Equals(RestrictedNumber<T> other)
{
return restricted_value.Equals(other);
}
public int CompareTo(RestrictedNumber<T> other)
{
return restricted_value.CompareTo(other);
}
public override string ToString()
{
return restricted_value.ToString();
}
}
public class RestrictedNumberExercise
{
public void ad_hoc_paces()
{
// declare with min, max, and value
var i = new RestrictedNumber<int>(1, 10, 15);
Debug.Assert(i == 10d);
Debug.Assert(i.UnrestrictedValue == 15d);
// declare implicitly
// my implementation initially sets min and max equal to value
RestrictedNumber<double> d = 15d;
d.Min = 1;
d.Max = 10;
Debug.Assert(i == 10d); // compare with other, "true" doubles
Debug.Assert(i.UnrestrictedValue == 15d); // still holds the original value
RestrictedNumber<decimal> m = new RestrictedNumber<decimal>(55.5m,55.5m,55.499m);
Debug.Assert(m == 55.5m);
Debug.Assert(m > m.UnrestrictedValue); // test out some other operators
Debug.Assert(m >= m.UnrestrictedValue); // we didn't have to define these
Debug.Assert(m + 10 == 65.5m); // you even get unary operators
RestrictedNumber<decimal> other = 50m;
Debug.Assert(m > other); // compare two of these objects
Debug.Assert(other <= m); // ...again without having to define the operators
Debug.Assert(m - 5.5m == other); // unary works with other Ts
Debug.Assert(m + other == 105.5m); // ...and with other RestrictedNumbers
Debug.Assert(55.5m - m == 0);
Debug.Assert(m - m == 0);
// passing to method that expects the primitive type
Func<float,float> square_float = f => f * f;
RestrictedNumber<float> restricted_float = 3;
Debug.Assert(square_float(restricted_float) == 9f);
// this sort of implementation is not without pitfalls
// there are other IEquatable<T> & IComaparable<T> types out there...
var restricted_string = new RestrictedNumber<string>("Abigail", "Xander", "Yolanda");
Debug.Assert(restricted_string == "Xander"); // this works
//Debug.Assert(restricted_string >= "Thomas"); // many operators not supported here
var pitfall = new RestrictedNumber<int>(1, 100, 200);
Debug.Assert(pitfall == 100);
pitfall = 200;
// Debug.Assert(pitfall == 100);
// FAIL -- using the implicit operator is effectively
// a factory method that returns a NEW RestrictedNumber
// with min and max initially equal to value (in my implementation)
Debug.Assert(pitfall == 200);
pitfall = 10;
Debug.Assert(pitfall.Min == 10 && pitfall.Max == 10);
pitfall++;
Debug.Assert(pitfall == 11); // d'oh!
Debug.Assert(pitfall.Min == 11 && pitfall.Max == 11); // "it goes up to eleven"
// if you need to change the input value for an existing
// RestrictedNumber, you could expose a SetValue method
// and make value not readonly
}
}
You can combine this approach with Bryan's fluent-ish interface and take this pretty far (though you probably don't really need to and this is all crazy overkill).
var n = Restrict<int>._(25).to_be.greater_than(50);
var p = Restrict<double>._(1234.567).to_be.greater_than(0d).and.less_than(50000d)