我正在考虑将Linq Expression用作词典中的键。但是,我担心我会得到奇怪的结果,因为我不知道Linq表达式如何确定Equality。
从Expression派生的类是否比较值相等或引用相等?或换句话说,
Expression<Func<object>> first = () => new object();
Expression<Func<object>> second = ()=>new object();
bool AreTheyEqual = first == second;
答案 0 :(得分:11)
您的测试会比较表达式。表达本身只提供参考平等;你的测试可能会显示“假”。要获得语义平等,你需要做很多工作,例如 - 是:
x => 123
和
y => 123
等效?作为原始测试,您可以比较ToString(),但这将非常脆弱。
答案 1 :(得分:0)
比较任何非值类型的对象(包括表达式)与==比较对象引用,因此它们不相等。然而,正如评论者指出的那样,字典将使用Equals
和GetHashCode
来确定相等性,这仍然会默认最终确定它们不相等。
您可以创建一个继承System.Linq.Expression
并覆盖GetHashCode
和Equals
的类,以某种方式使用结果,并将其用作词典的键。
答案 2 :(得分:0)
正如其他人所说,Expression的==运算符使用默认的“引用相等”检查 - “它们是否都是对堆中相同位置的引用?”。这意味着像您的示例之类的代码可能会返回false,因为您的表达式文字将被实例化为不同的Expression实例,而不管语义是否相等。使用lambdas作为事件处理程序也存在类似的挫败感:
MyEvent += (s, a) => DoSomething();
...
MyEvent -= (s, a) => DoSomething(); //<-- will NOT remove the added handler
检查语义相等是很棘手的。在这种特殊情况下,您可以访问表达式树的所有节点,并比较所有字符串,值类型和方法引用,以确定它们执行相同的操作。但是,通过检查,以下示例中的两个lambdas在语义上是等效的,但是您很难编写一个方法来证明它:
public void MyMethod() {...}
public void AnotherMethod { MyMethod(); };
...
Action one = () => MyMethod();
Action two = () => AnotherMethod();
var equal = one == two; // false