First off, I would like to say that caching expressions is something that should be done with utmost care and is extremely complex to implement as the example from the comments (this question) already shows. There is a reason why Equals
has not been overridden for expressions, because they are so complex to compare.
Some of the main issues with expressions when it comes to comparing them:
- Comparing expressions is about as expensive as compiling them
- When do you consider two expressions equal?
E.g.
y => y.MyProperty.AnotherProperty
x => x.MyProperty.AnotherProperty
Are the above two expressions equal? It depends on the use case (if you are analyzing code you might want to take the variable name into account). Also, consider the following example:
class BaseClass { int MyProperty { get; } }
class DerivedClass : BaseClass { }
Now lets say we have two expressions that are pretty much equal:
BaseClass x => x.MyProperty;
DerivedClass x => x.MyProperty;
Should these be considered equal? Probably not, but maybe in your case.
end of rant
Since you are dealing with MemberExpression
s you are probably doing something with property getters and setters or the like. In this case, it might be sufficient to use the Type
in combination with the MemberInfo
as a key for your Cache
object. Note that this only applies when ALL expressions are in the form of x => x.Property
without any nested access, casts or whatever.
In that case you could come up with something like this:
private struct MemberAccessKey
{
public readonly Type Type;
public readonly MemberInfo Member;
public MemberAccessKey(Type t, MemberInfo m)
{
Type = t; Member = m;
}
public override bool Equals(object obj)
{
if (!(obj is MemberAccessKey)) return false;
var other = (MemberAccessKey)obj;
return other.Type == Type && other.Member == Member;
}
public override int GetHashCode()
{
return Type.GetHashCode() ^ Member.GetHashCode();
}
}
And then instantiate it based on a MemberExpression:
TypeKey key = new TypeKey(typeof(TClass), memberExpression.Member);
Conclusion
- Don't do it because of performance reasons
- Don't do it because it only introduces bugs
- Don't do it!
- If you know that every single expression you create is in the form
x => x.MyProperty
then you might be able to use this as a key. Note that any other form will either crash or resolve to a duplicate key.