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.

questionAnswers(2)

yourAnswerToTheQuestion