Dlaczego ogólne i nie-ogólne struktury są traktowane inaczej podczas budowania wyrażenia, które podnosi operator == do wartości zerowej?
Wygląda to na błąd w podnoszeniu do null operandów na ogólnych strukturach.
Rozważ następującą strukturę fikcyjną, która zastępujeoperator==
:
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; }
}
Teraz rozważ następujące wyrażenia:
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;
Wszystkie trzy kompilują się i działają zgodnie z oczekiwaniami.
Kiedy są kompilowane (za pomocą.Compile()
) produkują następujący kod (sparafrazowany na angielski z IL):
Pierwsze wyrażenie, które trwa tylkoMyStruct
(nie dopuszcza się pustych) argumentów, po prostu wywołujeop_Equality
(nasza realizacjaoperator ==
)
Drugie wyrażenie, po skompilowaniu, tworzy kod, który sprawdza każdy argument, aby go sprawdzićHasValue
. Jeśli oba nie (oba równenull
), wracatrue
. Jeśli tylko jedna ma wartość, wracafalse
. W przeciwnym razie dzwoniop_Equality
na dwie wartości.
Trzecie wyrażenie sprawdza argumenty null, aby sprawdzić, czy ma wartość - jeśli nie, zwraca false. W przeciwnym razie dzwoniop_Equality
.
Jak na razie dobrze.
Następny krok: zrób dokładnie to samo z typem ogólnym - zmieńMyStruct
doMyStruct<T>
wszędzie w definicji typu i zmień ją naMyStruct<int>
w wyrażeniach.
Teraz trzecie wyrażenie się kompiluje, ale generuje wyjątek czasu wykonywaniaInvalidOperationException
z następującą wiadomością:
Operandy operatora 'Equal' nie pasują do parametrów metody 'op_Equality'.
Oczekiwałbym, że ogólne struktury zachowują się dokładnie tak samo, jak struktury nie generyczne, z całym opisanym powyżej zniesieniem wartości.
Moje pytania to:
Dlaczego istnieje różnica między strukturami rodzajowymi i nie-rodzajowymi?Jakie jest znaczenie tego wyjątku?Czy jest to błąd w C # / .NET?Pełny kod do reprodukcji todostępne na tej liście.