使用Expression <func <object>&gt;作为字典中的键</func <object>

时间:2010-12-13 11:28:54

标签: .net dictionary expression-trees

如何使用表达式&gt;作为字典中的键?

我刚刚开始玩Expression实例,并且不确定我想做什么是可能的。

似乎2个相同的表达式不相同,因为当我尝试时我可以使用表达式作为键将一个条目放入字典但是当我询问字典是否包含密钥时它返回false,除非我使用它相同的表达式实例。

TypeToTest test = new TypeToTest();
Expression<Func<object>> expression = ()=>test.PropertyA;
IDictionary<Expression<Func<object>>,bool> dictionary = new Dictionary<Expression<Func<object>>, bool> ();
dictionary[expression] = true;
Assert.That (dictionary.ContainsKey(expression), Is.True);
Assert.That (dictionary.ContainsKey(()=>test.PropertyA), Is.True);

上面的最后一行失败,当我希望它成功时。

目的是能够定义一组适用于对象的属性或方法的规则,以便我可以确定,例如,属性是否可编辑,或者字典中具有特定键的值是否可以被删除。我不希望在对象上有一个标志,它确定它是否可编辑(因为不同属性的editablity可能不同),另一个标志确定它是否可删除,而另一个类负责维护相关规则使用对象以便在将来扩展对象时可以添加更多规则来描述对象的组成部分的可编辑性/可访问性/可删除性。如果这是有道理的。

有类似的帖子here,但这似乎是基于属性名称的键,因为,我希望有可能键入方法和参数,所以我可以支持确定editablity基于密钥保存在字典中的对象。

这样的事情是可能的还是天空中的馅饼?

2 个答案:

答案 0 :(得分:4)

这是比较不同引用时的预期行为,其中该类型不会覆盖Equals或实现IEquatable<T>。您可以编写自定义比较器(可能只是简单地比较ToString())并将其传递到字典中 - 但IMO和Expression不是关键的好选择。

以下不一定是通过ToString()的强大用法;自行决定使用:

class Program {
    static void Main() {
        TypeToTest test = new TypeToTest();
        Expression<Func<object>> expression = () => test.PropertyA;
        IDictionary<Expression<Func<object>>, bool> dictionary =
            new Dictionary<Expression<Func<object>>, bool>(
               new ToStringComparer<Expression<Func<object>>>());
        dictionary[expression] = true;

        bool x = dictionary.ContainsKey(expression), // true
            y = dictionary.ContainsKey(() => test.PropertyA); // true
    }
}
class ToStringComparer<T> : IEqualityComparer<T> where T : class {
    public bool Equals(T x, T y) {
        if ((x == null && y == null) || ReferenceEquals(x,y)) return true;
        if (x == null || y == null) return false;
        return x.ToString() == y.ToString();
    }
    public int GetHashCode(T obj) {
        return obj == null ? 0 : obj.ToString().GetHashCode();
    }
}

答案 1 :(得分:2)

Expression类型的子类不会覆盖EqualsGetHashCode方法,因此很难用作字典键。您的字典使用引用相等,并且两次出现()=>test.PropertyA会生成两个不同的表达式树对象。

您可以编写自己的IEqualityComparer<Expression>实现,并将其传递给字典构造函数。在比较器中,您可以编写EqualsGetHashCode个方法来处理每个Expression类并比较它们的属性。