这看起来像是将泛型结构上的操作数提升为 null 的错误。
考虑以下虚拟结构,它覆盖operator==
:
struct MyStruct
{
private readonly int _value;
public MyStruct(int val) { this._value = val; }
public override bool Equals(object obj) { return false; }
public override int GetHashCode() { return base.GetHashCode(); }
public static bool operator ==(MyStruct a, MyStruct b) { return false; }
public static bool operator !=(MyStruct a, MyStruct b) { return false; }
}
现在考虑以下表达式:
Expression<Func<MyStruct, MyStruct, bool>> exprA =
(valueA, valueB) => valueA == valueB;
Expression<Func<MyStruct?, MyStruct?, bool>> exprB =
(nullableValueA, nullableValueB) => nullableValueA == nullableValueB;
Expression<Func<MyStruct?, MyStruct, bool>> exprC =
(nullableValueA, valueB) => nullableValueA == valueB;
所有三个都按预期编译和运行。
当它们被编译(使用.Compile()
)时,它们会生成以下代码(从 IL 解释为英语):
第一个只接受
MyStruct
(不可为空)args 的表达式,简单地调用op_Equality
(我们的实现operator ==
)第二个表达式在编译时会生成检查每个参数以查看它是否为 的代码
HasValue
。如果两者都不(都相等null
),则返回true
。如果只有一个有值,则返回false
。否则,调用op_Equality
这两个值。第三个表达式检查可空参数以查看它是否有值 - 如果没有,则返回 false。否则,调用
op_Equality
.
到目前为止,一切都很好。
下一步:对泛型类型执行完全相同的操作 - 更改类型MyStruct
定义MyStruct<T>
中的任何位置,并MyStruct<int>
在表达式中更改为。
现在第三个表达式编译但抛出运行时异常InvalidOperationException
并显示以下消息:
运算符“Equal”的操作数与方法“op_Equality”的参数不匹配。
我希望泛型结构的行为与非泛型结构完全相同,具有上述所有可空提升。
所以我的问题是:
- 为什么泛型和非泛型结构之间存在差异?
- 这个异常是什么意思?
- 这是 C#/.NET 中的错误吗?
此 gist 上提供了重现此内容的完整代码。