I am writing this neat class implementing IEqualityComparer, so that I can just pass any anonymous type to it (or actually any type with properties) and it will automatically compare the types by comparing the property values of the types.
public class CompareProperty<T> : IEqualityComparer<T>
{
private Type type;
private PropertyInfo propInfo;
private string _fieldName;
public string fieldName
{
get;
set;
}
public CompareProperty(string fieldName)
{
this.fieldName = fieldName;
}
public bool Equals<T>(T x, T y)
{
if (this.type == null)
{
type = x.GetType();
propInfo = type.GetProperty(fieldName);
}
object objX = propInfo.GetValue(x, null);
object objY = propInfo.GetValue(y, null);
return objX.ToString() == objY.ToString();
}
}
I thought this was a nice little helper function I could use many times.
In order to use this, I have to do:
var t = typeof(CompareProperty<>);
var g = t.MakeGenericType(infoType.GetType());
var c = g.GetConstructor(new Type[] {String.Empty.GetType()});
var obj = c.Invoke(new object[] {"somePropertyName"});
Fair enough, but what do I do with the obj variable it returns?
someEnumerable.Distinct(obj);
The overload of the distinct extension function does not accept this, because it does not see a IEqualityComparer type, it only sees an object, of course.
someEnumerable.Distinct((t) obj);
someEnumerable.Distinct(obj as t);
This also doesn't work. Type/Namespace not found (red underline).
How do I get this straight?
I'll first provide a solution for non-anonymous types and afterwards extend it to work for anonymous types as well. Hopefully, it will help you to understand what people were trying to say in comments to your question.
My "universal"
IEqualityComparer<>
looks like this:Say that we want to use it with non-anonymous type first, like
Person
:The usage would be quite straightforward:
As you can see, to use the
PropertyComparer<T>
, we need to specify the type (theT
) instances of which are going to be compared against each other. What would theT
be when dealing with anonymous types? Since they are generated at runtime, you cannot use the comparer by directly creating its instance, simply because you do not know theT
at compile time. Instead, you need to use type-inference to let the C# compiler inferT
from context on its own. Neat way to do this is to write the following extension method:Now it will also work with anonymous types:
All of a sudden, there is no need to specify the exact type the query is dealing with anywhere, since C# compiler is smart enough to infer it from the context (which, in this case, is being provided from the type of
source
parameter in the extension method).Hope this will help you.
Just add own validations.
Class with extension method:
Usage: