(Nawiązując do uwag zaakceptowanej odpowiedzi.)
Tak, to jest bardzo, bardzo mylące część spec. Cały fragment dotyczący "obejmujących typy" jest w szczególności głęboko błędny. Od kilku lat próbuję znaleźć czas, aby całkowicie przepisać całą tę sekcję w coś bardziej spójnego, ale nigdy nie było to wystarczająco priorytetowe.
Zasadniczo mamy tutaj sprzeczność; my powiedzieć, że nie ma żadnych niejawnych konwersji zdefiniowanych przez użytkownika z udziałem interfejsów, ale wyraźnie, że nie jest to prawdą w tym przypadku; istnieje niejawna konwersja z IC na zdefiniowaną przez użytkownika do Foo<IC>
, o czym świadczy fakt, że ciąg przechodzi do Foo<IC>
przez tę konwersję.
Co tak naprawdę powinien być podkreślając lepsze jest to, że linia cytowany:
W szczególności nie jest możliwe przedefiniować już istniejącego niejawny lub wyraźnej konwersji.
To właśnie motywuje tę całość; pragnienie, aby nie pozwolić ci kiedykolwiek myśleć, że robisz test typu zachowującego reprezentację, gdy w rzeczywistości wywołujesz metodę zdefiniowaną przez użytkownika. Rozważmy na przykład tę odmianę:
interface IBar {}
interface IFoo : IBar {}
class Foo<T> : IFoo
{
public static explicit operator Foo<T>(T input) { whatever }
}
class Blah : Foo<IBar> {}
...
IBar bar = new Blah();
Foo<IBar> foo = (Foo<IBar>)bar;
Teraz czy to zadzwonić do zdefiniowanego przez użytkownika wyraźnej konwersji, czy nie? Obiekt naprawdę pochodzi od Foo, więc możesz mieć nadzieję, że tak się nie stanie; powinien to być prosty test typu i przypisanie referencji, a nie wywołanie metody pomocniczej. Rzut na wartość interfejsu jest zawsze traktowany jako test typu, ponieważ prawie zawsze jest możliwe, że obiekt rzeczywiście jest tego typu i naprawdę implementuje ten interfejs. Nie chcemy odmówić ci możliwości zrobienia taniej konwersji zachowującej reprezentację.
Wow. Cóż za dziwne wymaganie. Chciałbym usłyszeć od Lipperta, Skeeta lub innego eksperta od C#, dlaczego typy interfejsu nie działają w tym celu; z pewnością musi być dobry powód tego dziwactwa. –
Po kilku eksperymentach, wydaje mi się, że kluczowe są tutaj interfejsy. Co dziwne, wydaje się, że nie jest to mentalny skok, aby kompilator mógł wymyślić, co robić często. Hmm. –
Byłbym bardzo zainteresowany wyjaśnieniem, w jaki sposób kompiluje się pierwsza próbka. Biorąc pod uwagę zasady w sekcji 6.4.4, nie widzę sposobu, w jaki wybrał on 'Foo', ponieważ 'ICloneable' nie obejmuje' ciągu' (ponieważ 'ICloneable' jest interfejsem) i' Foo 'jest nieobjęte "Foo " (ponieważ nie ma żadnej niejawnej konwersji z 'Foo ' na 'Foo '). Może 6.1.9 "Niejawne konwersje z udziałem parametrów typu" wchodzi w grę w jakiś sposób? –
zinglon