创建以memberexpression为键的字典
本文关键字:字典 memberexpression 创建 | 更新日期: 2023-09-27 18:21:17
我想为我的对象和表达式创建一个缓存。通过以下代码,他运行true所有元素,之后他将能够使用字典中的表达式/对象。他没有这样做,而是使用相同的对象将成员表达式再次添加到字典中。
有可能创建一个带有成员表达式的字典吗?我在这里做错了什么?
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;
}
注意:正如你从代码中看到的,我想创建一个缓存,所以我只需要编译函数一次。
首先,我想说的是,缓存表达式是一件应该非常小心的事情,并且实现起来非常复杂,正如注释(这个问题)中的示例所示。表达式没有重写Equals
是有原因的,因为它们比较起来太复杂了。
表达式在比较时的一些主要问题:
- 比较表达式和编译表达式一样昂贵
- 你什么时候认为两个表达式相等
例如
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
,您可能正在使用属性getter和setter或类似的东西。在这种情况下,将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
,那么您可能可以将其用作键。请注意,任何其他表单都将崩溃或解析为重复的密钥