创建以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;
}

注意:正如你从代码中看到的,我想创建一个缓存,所以我只需要编译函数一次。

创建以memberexpression为键的字典

首先,我想说的是,缓存表达式是一件应该非常小心的事情,并且实现起来非常复杂,正如注释(这个问题)中的示例所示。表达式没有重写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或类似的东西。在这种情况下,将TypeMemberInfo组合用作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);

结论

  1. 不要因为性能原因而这么做
  2. 不要这样做,因为它只会引入错误
  3. 不要这么做
  4. 如果您知道您创建的每个表达式的形式都是x => x.MyProperty,那么您可能可以将其用作键。请注意,任何其他表单都将崩溃或解析为重复的密钥