使用memberexpression作为键创建字典

时间:2014-09-10 12:17:56

标签: c# dictionary lambda expression

我想为我的对象和表达式创建一个缓存。使用以下代码,他运行所有元素,之后他将能够使用字典中的表达式/对象。他没有这样做,而是将成员表达式再次添加到具有相同对象的字典中。

是否可以使用成员表达式创建字典,我在这里做错了什么?

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;
}

注意:从代码中我可以看到我想创建一个缓存,所以我只需要编译一次。

1 个答案:

答案 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,因此您可能正在使用属性获取器和设置器等。在这种情况下,将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格式,那么您可以将其用作关键字。请注意,任何其他表单都将崩溃或解析为重复键。