Почему общие и неуниверсальные структуры обрабатываются по-разному при построении выражения, которое поднимает оператор == до нуля?
Это похоже на ошибку при поднятии до нуля операндов на общих структурах.
Рассмотрим следующую фиктивную структуру, которая переопределяет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
со следующим сообщением:
Операнды для оператора «Равный» не соответствуют параметрам метода «op_Equality».
Я ожидал бы, что родовые структуры будут вести себя точно так же, как и неуниверсальные, со всеми отменяемыми значениями, описанными выше.
Итак, мои вопросы:
Почему существует разница между общими и неуниверсальными структурами?В чем смысл этого исключения?Это ошибка в C # /. NET?Полный код для воспроизведения этогодоступно в этом суть.