我想为我的对象和表达式创建一个缓存。使用以下代码,他运行所有元素,之后他将能够使用字典中的表达式/对象。他没有这样做,而是将成员表达式再次添加到具有相同对象的字典中。
是否可以使用成员表达式创建字典,我在这里做错了什么?
private static readonly IDictionary<MemberExpression, object> Cache = new Dictionary<MemberExpression, object>();
private static Func<TClass, TProperty> GetCachedMemberFunction<TClass, TProperty>(
Expression<Func<TClass, TProperty>> member)
{
Func<TClass, TProperty> func;
var memberExpression = member.Body as MemberExpression;
if (Cache.ContainsKey(memberExpression))
{
func = (Func<TClass, TProperty>)Cache[memberExpression];
}
else
{
func = member.Compile();
Cache[memberExpression] = func;
}
return func;
}
注意:从代码中我可以看到我想创建一个缓存,所以我只需要编译一次。
答案 0 :(得分:1)
首先,我想说缓存表达式是应该非常谨慎地完成的,并且实现起来非常复杂,正如评论(this question)中的示例已经显示的那样。有一个原因是Equals
没有被表达式覆盖,因为它们比较复杂。
比较它们时表达式的一些主要问题:
E.g。
y => y.MyProperty.AnotherProperty
x => x.MyProperty.AnotherProperty
以上两个表达式是否相等?这取决于用例(如果您正在分析代码,则可能需要考虑变量名称)。另外,请考虑以下示例:
class BaseClass { int MyProperty { get; } }
class DerivedClass : BaseClass { }
现在假设我们有两个非常相似的表达式:
BaseClass x => x.MyProperty;
DerivedClass x => x.MyProperty;
这些应该被认为是平等的吗?可能不是,但也许在你的情况下。
咆哮结束
由于您正在处理MemberExpression
s,因此您可能正在使用属性获取器和设置器等。在这种情况下,将Type
与MemberInfo
结合使用作为Cache
对象的键可能就足够了。 请注意,这仅适用于所有表达式都采用x => x.Property
形式而没有任何嵌套访问,强制转换或其他任何内容的情况。
在这种情况下,你可以想出这样的东西:
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();
}
}
然后基于MemberExpression实例化它:
TypeKey key = new TypeKey(typeof(TClass), memberExpression.Member);
<强>结论强>
x => x.MyProperty
格式,那么您可以将其用作关键字。请注意,任何其他表单都将崩溃或解析为重复键。