Is there a way to declare that an extending class must override a particular operator? For example, given class 'BaseClass' and A : BaseClass, B : BaseClass, is there a way to force both 'A' and 'B' to define an operator override for >= .
You cannot force derived classes to define an override for an operator because operators are static.
You could do something like this:
using System;
abstract class BaseClass {
public static bool operator >= (BaseClass x, BaseClass y) {
if (x is null || y is null) {
throw new ArgumentException("Cannot compare null values.");
}
return x.GreaterEqual(y);
}
// If you define an operator, you must define its matching operator as well.
// Just throwing NotImplementedException for the example.
public static bool operator <= (BaseClass x, BaseClass y) {
throw new NotImplementedException();
}
public abstract bool GreaterEqual(BaseClass y);
}
class A : BaseClass {
public int SomeValue;
public override bool GreaterEqual(BaseClass y) {
A other = y as A;
if (other is null) {
throw new ArgumentException("Cannot compare null or non-A values.");
}
return SomeValue >= other.SomeValue;
}
}
class Program {
static void Main(string[] args) {
A a1 = new A { SomeValue = 1 };
A a2 = new A { SomeValue = 2 };
bool test = a1 >= a2;
}
}
This would force your derived classes to define the GreaterEqual method.
This question already has answers here:
Is there a constraint that restricts my generic method to numeric types?
(24 answers)
Closed 9 years ago.
I've got a method like this:
public static bool IsPercentage<T>(T value) where T : IComparable
{
return value.CompareTo(0) >= 0 && value.CompareTo(1) <= 0;
}
I would like to use this to validate if any number falls in the range 0 <= N <= 1. However this only works with integers since CompareTo only operates on equal types. Is there a different way to do this?
well you could use Convert.ToDecimal, then you don't need to be generic:
public static bool IsPercentage(Object value)
{
decimal val = 0;
try
{
val = Convert.ToDecimal(value);
}
catch
{
return false;
}
return val >= 0m && val <= 1m;
}
You can use Expression Tree to do this. Consider helper, static class
static class NumericHelper<T>
{
public static T Zero { get; private set; }
public static T One { get; private set; }
static NumericHelper()
{
Zero = default(T);
One = Expression.Lambda<Func<T>>(
Expression.Convert(
Expression.Constant(1),
typeof(T)
)
).Compile()();
}
}
It generates (T)1 cast at runtime and assign result to One property. Because static constructor is fired only once code necessary to generate properly typed 1 value will be executed only once for every T.
public static bool IsPercentage<T>(T value) where T : IComparable
{
return value.CompareTo(NumericHelper<T>.Zero) >= 0 && value.CompareTo(NumericHelper<T>.One) <= 0;
}
Ofc, it will fail if you try to call it with type T which don't support (T)1 conversion.
I have this class:
public class SmartTable : DataTable
{
public string this[int Row, int Column] { ... }
public string this[int Row, string Column] { ... }
}
and i want to add an implicit operator on THIS[,]
then i could use:
string s = smartT[a,b];
or
int i = smartT[a,b];
I googled this but even I don't know how to search it.
I tried (based on IntelliSense) declare something like:
public static implicit operator int[int r, int c](...) {...}
or
public static implicit operator int (SmartTable sm, int a, int b)
and don't work.
Thanks
=== Edit ===
This is a DataTable, and a table have strings, integers, ...
I want to avoid put Convert.To--(...) every time i use this table...
If I try to put a Field on a int, is because it's a integer field...
A solution I'm using is create iGet(int C, int R), sGet(...), dGet(...)
If you can change your SmartTable design to return or work with a custom class instead of the primitive string type, then you can add your own implicit conversions to int or string.
public class SmartTable : DataTable
{
//dummy/hard-coded values here for demonstration purposes
public DataValue this[int Row, int Column] { get { return new DataValue() {Value="3"}; } set { } }
public DataValue this[int Row, string Column] { get { return new DataValue() {Value="3"}; } set { } }
}
public class DataValue
{
public string Value;
public static implicit operator int(DataValue datavalue)
{
return Int32.Parse(datavalue.Value);
}
public static implicit operator string(DataValue datavalue)
{
return datavalue.Value;
}
}
And some usage:
string s = smartT[0, 0];
int i = smartT[0, 0];
Console.WriteLine(s);//"3"
Console.WriteLine(i);//3
Note that this kinda flies in the face of using implicit operators. For example, if your DataValue.Value is non-convertable to int (for example, if it were "Hello World!") it would throw an exception which is generally against the best practices and unexpected for developers leveraging your API.
I am trying to get list of unique elements for a custom datatype. I seriously couldn't figure out why this doesn't work. The control never reaches the Equals implementation in the below code. Could someone please help with this?
public class customobj : IEqualityComparer<customobj>
{
public string str1;
public string str2;
public customobj(string s1, string s2)
{
this.str1 = s1; this.str2 = s2;
}
public bool Equals(customobj obj1, customobj obj2)
{
if ((obj1 == null) || (obj2 == null))
{
return false;
}
return ((obj1.str1.Equals(obj2.str1)) && (obj2.str2.Equals(obj2.str2)));
}
public int GetHashCode(customobj w)
{
if (w != null)
{
return ((w.str1.GetHashCode()) ^ (w.str2.GetHashCode()));
}
return 0;
}
}
And below is the part where i am trying to retrieve distinct elements of list.
List<customobj> templist = new List<customobj> { };
templist.Add(new customobj("10", "50"));
templist.Add(new customobj("10", "50"));
List<customobj> dist = templist.Distinct().ToList();
Your class does not override base Equals() from object class, and Distinct() is using it.
Try overriding base Equals, and calling your custom Equals(Rectangle obj1, Rectangle obj2) from there.
Also, if you want to inherit from typed comparer, use IEquatable<T> , but not IEqualityComparer<Rectangle>
bool Equals(Rectangle obj1, Rectangle obj2)
is a static method of Object, so it can't be overridden.
You must override the instance Equals instead.
public override bool Equals(Object obj) {
...
}
If you want to implement IEqualityComparer in Rectangle's class you should to write something this:
List<Rectangle> dist = templist.Distinct(new Reclangle("","")).ToList();
Usually it is implements through an RectangleComparer class:
class RectangleComparer : IEqualityComparer<Rectangle>
{
public static IEqualityComparer<Rectangle> Instance { get {...} }
...
}
List<Rectangle> dist = templist.Distinct(RectangleComparer.Instance).ToList();
Or override GetHashCode and Equals =)
You are implementing the wrong interface. Your class implements IEqualityComparer<Rectangle>, not IEquatable<Rectangle>. Unless you pass in an IEqualityComparer to Distinct, it will use either IEquatable.Equals (if youe class implements it) or Object.Equals.
public class Rectangle : IEquatable<Rectangle>
{
public string width;
public string height;
public Rectangle(string s1, string s2)
{
this.width = s1; this.height = s2;
}
`IEquatable.Equals
public bool Equals(Rectangle obj2)
{
if (obj2 == null)
{
return false;
}
return ((this.width.Equals(obj2.width)) && (this.height.Equals(obj2.height)));
}
`override of object.Equals
public override bool Equals(Object(o2)
{
if(typeof(o2) == typeof(Rectangle))
return ((Rectangle)this.Equals((Rectangle)o2);
return false;
}
'override of object.GetHashCode
public override int GetHashCode()
{
return ((this.width.GetHashCode()) ^ (thisw.height.GetHashCode()));
}
}
Also, is there a particular reason why your width and height are strings and not numeric types? It seems very odd, and could lead to weird bugs such as assuming that "100" and "0100" and " 100 " are equal, when in fact they are distinct strings and will have different hash codes.
I have some bells in my database with the same number. I want to get all of them without duplication. I created a compare class to do this work, but the execution of the function causes a big delay from the function without distinct, from 0.6 sec to 3.2 sec!
Am I doing it right or do I have to use another method?
reg.AddRange(
(from a in this.dataContext.reglements
join b in this.dataContext.Clients on a.Id_client equals b.Id
where a.date_v <= datefin && a.date_v >= datedeb
where a.Id_client == b.Id
orderby a.date_v descending
select new Class_reglement
{
nom = b.Nom,
code = b.code,
Numf = a.Numf,
})
.AsEnumerable()
.Distinct(new Compare())
.ToList());
class Compare : IEqualityComparer<Class_reglement>
{
public bool Equals(Class_reglement x, Class_reglement y)
{
if (x.Numf == y.Numf)
{
return true;
}
else { return false; }
}
public int GetHashCode(Class_reglement codeh)
{
return 0;
}
}
Your GetHashCode implementation always returns the same value. Distinct relies on a good hash function to work efficiently because it internally builds a hash table.
When implementing interfaces of classes it is important to read the documentation, to know which contract you’re supposed to implement.1
In your code, the solution is to forward GetHashCode to Class_reglement.Numf.GetHashCode and implement it appropriately there.
Apart from that, your Equals method is full of unnecessary code. It could be rewritten as follows (same semantics, ¼ of the code, more readable):
public bool Equals(Class_reglement x, Class_reglement y)
{
return x.Numf == y.Numf;
}
Lastly, the ToList call is unnecessary and time-consuming: AddRange accepts any IEnumerable so conversion to a List isn’t required. AsEnumerable is also redundant here since processing the result in AddRange will cause this anyway.
1 Writing code without knowing what it actually does is called cargo cult programming. It’s a surprisingly widespread practice. It fundamentally doesn’t work.
Try This code:
public class GenericCompare<T> : IEqualityComparer<T> where T : class
{
private Func<T, object> _expr { get; set; }
public GenericCompare(Func<T, object> expr)
{
this._expr = expr;
}
public bool Equals(T x, T y)
{
var first = _expr.Invoke(x);
var sec = _expr.Invoke(y);
if (first != null && first.Equals(sec))
return true;
else
return false;
}
public int GetHashCode(T obj)
{
return obj.GetHashCode();
}
}
Example of its use would be
collection = collection
.Except(ExistedDataEles, new GenericCompare<DataEle>(x=>x.Id))
.ToList();
If you want a generic solution that creates an IEqualityComparer for your class based on a property (which acts as a key) of that class have a look at this:
public class KeyBasedEqualityComparer<T, TKey> : IEqualityComparer<T>
{
private readonly Func<T, TKey> _keyGetter;
public KeyBasedEqualityComparer(Func<T, TKey> keyGetter)
{
if (default(T) == null)
{
_keyGetter = (x) => x == null ? default : keyGetter(x);
}
else
{
_keyGetter = keyGetter;
}
}
public bool Equals(T x, T y)
{
return EqualityComparer<TKey>.Default.Equals(_keyGetter(x), _keyGetter(y));
}
public int GetHashCode(T obj)
{
TKey key = _keyGetter(obj);
return key == null ? 0 : key.GetHashCode();
}
}
public static class KeyBasedEqualityComparer<T>
{
public static KeyBasedEqualityComparer<T, TKey> Create<TKey>(Func<T, TKey> keyGetter)
{
return new KeyBasedEqualityComparer<T, TKey>(keyGetter);
}
}
For better performance with structs there isn't any boxing.
Usage is like this:
IEqualityComparer<Class_reglement> equalityComparer =
KeyBasedEqualityComparer<Class_reglement>.Create(x => x.Numf);
Just code, with implementation of GetHashCode and NULL validation:
public class Class_reglementComparer : IEqualityComparer<Class_reglement>
{
public bool Equals(Class_reglement x, Class_reglement y)
{
if (x is null || y is null))
return false;
return x.Numf == y.Numf;
}
public int GetHashCode(Class_reglement product)
{
//Check whether the object is null
if (product is null) return 0;
//Get hash code for the Numf field if it is not null.
int hashNumf = product.hashNumf == null ? 0 : product.hashNumf.GetHashCode();
return hashNumf;
}
}
Example:
list of Class_reglement distinct by Numf
List<Class_reglement> items = items.Distinct(new Class_reglementComparer());
The purpose of this answer is to improve on previous answers by:
making the lambda expression optional in the constructor so that full object equality can be checked by default, not just on one of the properties.
operating on different types of classes, even complex types including sub-objects or nested lists. And not only on simple classes comprising only primitive type properties.
Not taking into account possible list container differences.
Here, you'll find a first simple code sample that works only on simple types (the ones composed only by primitif properties), and a second one that is complete (for a wider range of classes and complex types).
Here is my 2 pennies try:
public class GenericEqualityComparer<T> : IEqualityComparer<T> where T : class
{
private Func<T, object> _expr { get; set; }
public GenericEqualityComparer() => _expr = null;
public GenericEqualityComparer(Func<T, object> expr) => _expr = expr;
public bool Equals(T x, T y)
{
var first = _expr?.Invoke(x) ?? x;
var sec = _expr?.Invoke(y) ?? y;
if (first == null && sec == null)
return true;
if (first != null && first.Equals(sec))
return true;
var typeProperties = typeof(T).GetProperties();
foreach (var prop in typeProperties)
{
var firstPropVal = prop.GetValue(first, null);
var secPropVal = prop.GetValue(sec, null);
if (firstPropVal != null && !firstPropVal.Equals(secPropVal))
return false;
}
return true;
}
public int GetHashCode(T obj) =>
_expr?.Invoke(obj).GetHashCode() ?? obj.GetHashCode();
}
I know we can still optimize it (and maybe use a recursive?)..
But that is working like a charm without this much complexity and on a wide range of classes. ;)
Edit: After a day, here is my $10 attempt:
First, in a separate static extension class, you'll need:
public static class CollectionExtensions
{
public static bool HasSameLengthThan<T>(this IEnumerable<T> list, IEnumerable<T> expected)
{
if (list.IsNullOrEmptyCollection() && expected.IsNullOrEmptyCollection())
return true;
if ((list.IsNullOrEmptyCollection() && !expected.IsNullOrEmptyCollection()) || (!list.IsNullOrEmptyCollection() && expected.IsNullOrEmptyCollection()))
return false;
return list.Count() == expected.Count();
}
/// <summary>
/// Used to find out if a collection is empty or if it contains no elements.
/// </summary>
/// <typeparam name="T">Type of the collection's items.</typeparam>
/// <param name="list">Collection of items to test.</param>
/// <returns><c>true</c> if the collection is <c>null</c> or empty (without items), <c>false</c> otherwise.</returns>
public static bool IsNullOrEmptyCollection<T>(this IEnumerable<T> list) => list == null || !list.Any();
}
Then, here is the updated class that works on a wider range of classes:
public class GenericComparer<T> : IEqualityComparer<T> where T : class
{
private Func<T, object> _expr { get; set; }
public GenericComparer() => _expr = null;
public GenericComparer(Func<T, object> expr) => _expr = expr;
public bool Equals(T x, T y)
{
var first = _expr?.Invoke(x) ?? x;
var sec = _expr?.Invoke(y) ?? y;
if (ObjEquals(first, sec))
return true;
var typeProperties = typeof(T).GetProperties();
foreach (var prop in typeProperties)
{
var firstPropVal = prop.GetValue(first, null);
var secPropVal = prop.GetValue(sec, null);
if (!ObjEquals(firstPropVal, secPropVal))
{
var propType = prop.PropertyType;
if (IsEnumerableType(propType) && firstPropVal is IEnumerable && !ArrayEquals(firstPropVal, secPropVal))
return false;
if (propType.IsClass)
{
if (!DeepEqualsFromObj(firstPropVal, secPropVal, propType))
return false;
if (!DeepObjEquals(firstPropVal, secPropVal))
return false;
}
}
}
return true;
}
public int GetHashCode(T obj) =>
_expr?.Invoke(obj).GetHashCode() ?? obj.GetHashCode();
#region Private Helpers
private bool DeepObjEquals(object x, object y) =>
new GenericComparer<object>().Equals(x, y);
private bool DeepEquals<U>(U x, U y) where U : class =>
new GenericComparer<U>().Equals(x, y);
private bool DeepEqualsFromObj(object x, object y, Type type)
{
dynamic a = Convert.ChangeType(x, type);
dynamic b = Convert.ChangeType(y, type);
return DeepEquals(a, b);
}
private bool IsEnumerableType(Type type) =>
type.GetInterface(nameof(IEnumerable)) != null;
private bool ObjEquals(object x, object y)
{
if (x == null && y == null) return true;
return x != null && x.Equals(y);
}
private bool ArrayEquals(object x, object y)
{
var firstList = new List<object>((IEnumerable<object>)x);
var secList = new List<object>((IEnumerable<object>)y);
if (!firstList.HasSameLengthThan(secList))
return false;
var elementType = firstList?.FirstOrDefault()?.GetType();
int cpt = 0;
foreach (var e in firstList)
{
if (!DeepEqualsFromObj(e, secList[cpt++], elementType))
return false;
}
return true;
}
#endregion Private Helpers
We can still optimize it but it worth give it a try ^^.
The inclusion of your comparison class (or more specifically the AsEnumerable call you needed to use to get it to work) meant that the sorting logic went from being based on the database server to being on the database client (your application). This meant that your client now needs to retrieve and then process a larger number of records, which will always be less efficient that performing the lookup on the database where the approprate indexes can be used.
You should try to develop a where clause that satisfies your requirements instead, see Using an IEqualityComparer with a LINQ to Entities Except clause for more details.
IEquatable<T> can be a much easier way to do this with modern frameworks.
You get a nice simple bool Equals(T other) function and there's no messing around with casting or creating a separate class.
public class Person : IEquatable<Person>
{
public Person(string name, string hometown)
{
this.Name = name;
this.Hometown = hometown;
}
public string Name { get; set; }
public string Hometown { get; set; }
// can't get much simpler than this!
public bool Equals(Person other)
{
return this.Name == other.Name && this.Hometown == other.Hometown;
}
public override int GetHashCode()
{
return Name.GetHashCode(); // see other links for hashcode guidance
}
}
Note you DO have to implement GetHashCode if using this in a dictionary or with something like Distinct.
PS. I don't think any custom Equals methods work with entity framework directly on the database side (I think you know this because you do AsEnumerable) but this is a much simpler method to do a simple Equals for the general case.
If things don't seem to be working (such as duplicate key errors when doing ToDictionary) put a breakpoint inside Equals to make sure it's being hit and make sure you have GetHashCode defined (with override keyword).