Given an lambda
expression, I need a way to store a compiled delegate in a dictionary, so i don't need to compile them each time.
My first attempt was caching delegates by expression converted to string:
class ExpressionEqualityComparer : IEqualityComparer<Expression>
{
public bool Equals(Expression a, Expression b)
{
return a.ToString().Equals(b.ToString());
}
public int GetHashCode(Expression e)
{
return e.ToString().GetHashCode();
}
}
void Main()
{
var e1 = (Expression<Func<object, string>>)(o => ((Model)o).Prop);
Console.WriteLine(e1.ToString());
d.Add(e1, e1.Compile());
var e2 = (Expression<Func<object, string>>)(o => ((Model2)o).Prop);
try
{
d.Add(e2, e2.Compile());
}
catch
{
// ArgumentException. An element with the same key already exists in the Dictionary< TKey, TValue >.
}
Console.WriteLine(e2.ToString());
Console.WriteLine(d.Count);
}
Dictionary<Expression, System.Func<object, string>> d = new Dictionary<Expression, System.Func<object, string>>(new ExpressionEqualityComparer());
class Model
{
public string Prop { get; set; }
}
class Model2
{
public string Prop { get; set; }
}
Output:
o => Convert(o).Prop
o => Convert(o).Prop
1
This approach does not work because Expression.ToString()
is not detailed enough to provide equality, and it's not reliable since there is no guarantee about the ToString
implementation in general.
How to implement Equals(Expression, Expression)
and GetHashCode(Expression)
correctly without visiting the expression nodes?
If it's not possible with expression instance, is it possible with some other language construct, wrapping the original expression, which can be used to obtain the said expression?
The absolute requirement, which makes this question different from duplicates: Working in constant amortized time proportional to average size of the expression, which is the requirement to keep original hash function algorithmic properties.