我想确保表达式不会被多次编译,所以我试着在字典中记住它们:
static Dictionary<int, object> dict = new Dictionary<int, object>();
static T testmethod<T>(Expression<Func<T>> e) {
object result;
if (!dict.TryGetValue(1, out result)) {
result = e.Compile();
dict.Add(1, e);
}
return ((Func<T>)result)();
}
static void Main(string[] args) {
var firstTest = testmethod(() => default(int));
var secondTest = testmethod(() => default(int));
}
虽然testmethod
的第一次调用没有错误,但第二次调用因InvalidCastException
(翻译)而崩溃:
System.Linq.Expressions.Expression`1[System.Func`1[System.In32]] cannot be converted to System.Func`1[System.In32]
该消息表明该表达式根本没有编译,但为什么它第一次起作用呢?我错过了什么?
答案 0 :(得分:4)
e.Compile
会返回Func<T>
,但您要将源Expression<Func<T>>
添加到字典中,然后您尝试将其转换为Func<T>
第二个电话。将已编译的Func<T>
添加到dict
代替:
dict.Add(1, result);
答案 1 :(得分:3)
result = e.Compile(); dict.Add(1, e);
您没有将委托(已编译的表达式)添加到字典中,而是将表达式本身添加到字典中。在第二行中,将e
替换为result
。
return ((Func<T>)result)();
您希望result
成为代表。仅当字典没有包含键1
的值并且上述两行被执行时才会出现这种情况。如果字典确实包含一个值(在第二次迭代中),那么result
将是一个表达式,由于dict.Add(1, e);
。
PS:您可能通过将字典值限制为Delegate
而不是object
来解决该错误。