8

Więc czytam Eric Lippert's 'Constraints are not part of the signature', a teraz rozumiem, że specyfikacja określa, że ​​ograniczenia typu są sprawdzane PO rozdzielczości przeciążenia, ale nadal nie jest jasne, dlaczego tak MUSI być w tym przypadku. Poniżej jest przykład Erica:Dlaczego ograniczenia typu nie są częścią podpisu metody?

nie skompilować, ponieważ rozdzielczość przeciążenie dla: Foo(new Giraffe()) wnioskuje że Foo<Giraffe> to najlepszy mecz przeciążenie ale potem ograniczenia typu fail i błąd czasu kompilacji jest wyrzucane. W słowach Erica:

Zasada tutaj jest rozdzielczość przeciążania (i wnioskowania typu metody) znaleźć najlepsze możliwe dopasowanie między listą argumentów i listę formalnych parametrów każdej metody. Oznacza to, że patrzą na podpis metody kandydata.

Ograniczenia typu NIE są częścią podpisu, ale dlaczego nie mogą być? Jakie są scenariusze, w których złym pomysłem jest uwzględnienie ograniczeń typu w podpisie? Czy jest to trudne lub niemożliwe do zrealizowania? Nie jestem zwolennikiem tego, że jeśli najlepiej wybrane przeciążenie jest z jakiegokolwiek powodu niemożliwe do wywołania, w milczeniu powrócić do drugiego najlepszego; Nienawidziłbym tego. Po prostu staram się zrozumieć, dlaczego ograniczenia typu nie mogą być wykorzystywane do wpływania na wybór najlepszego przeciążenia.

Wyobrażam sobie, że wewnętrznie w C# kompilator, jedynie rozdzielczości przeciążeniowych (to nie na stałe przepisać metody), co następuje:

static void Foo<T>(T t) where T : Reptile { } 

zostaje zwerbowany do:

static void Foo(Reptile t) { } 

Dlaczego nie możesz "wciągnąć" wiązań typu do listy formalnych parametrów? W jaki sposób zmienia to podpis w jakikolwiek zły sposób? Mam wrażenie, że tylko wzmacnia podpis. Wtedy Foo<Reptile> nigdy nie będzie uważane za kandydata na przeciążenie.

Edytuj 2: Nic dziwnego, że moje pytanie było tak mylące. Nie czytałem poprawnie bloga Erica i zacytowałem niewłaściwy przykład. Edytowałem w przykładzie, który uważam za bardziej odpowiedni. Zmieniłem też tytuł na bardziej szczegółowy. To pytanie nie wydaje się tak proste, jak sobie wyobrażałem, być może brakuje mi jakiejś ważnej koncepcji. Jestem mniej pewny, że jest to materiał stackoverflow, może być najlepsze, aby to pytanie/dyskusja zostały przeniesione gdzie indziej.

+1

Fragment o Legwanach, który zacytowałeś na górze twojego pytania, miał na celu zilustrowanie sytuacji, w której typ wnioskowania * nie * bierze pod uwagę ograniczenie, a mianowicie ograniczenie T w C , a zatem ostateczna rozdzielczość przeciążania * * w tym przykładzie metoda * nietypowa *. Czy jesteś * pewien *, który jest istotnym fragmentem artykułu, który zamierzasz zacytować, aby zadać to pytanie? Pozostała część pytania wydaje się nie wynikać z tego logicznie. –

+1

Myślę, że raczej chciałeś zapytać, dlaczego to jest, gdy wnioskowanie o typie * się powiedzie *, ale określa typ, który narusza ograniczenie * w parametrze typu metody *, dlaczego nie można rozwiązać problemu z przeciążeniem, gdy istnieje alternatywa. Stwierdzam, że to pytanie jest bardzo mylące, ale z drugiej strony jest to myląca część specyfikacji. –

+0

Masz rację. Błędnie odczytałem Twojego bloga i użyłem niewłaściwego przykładu. Nic dziwnego, że moje pytanie było tak zagmatwane. Próbowałem wyjaśnić moje pytanie najlepiej jak potrafię; Przeczytam także niektóre z twoich innych blogów, aby sprawdzić, czy mogę poprawić moją wiedzę na ten temat. – Daryl

Odpowiedz

4

C# kompilator nie musi rozważyć ograniczenia typu jako część jak podpis metody, ponieważ nie są one częścią podpisu metoda CLR. Byłoby katastrofalne, gdyby rezolucja o przeciążeniu działała inaczej dla różnych języków (głównie ze względu na dynamiczne wiązanie, które może się zdarzyć w czasie uruchamiania i nie powinna się różnić od jednego języka do drugiego, albo wszystkie piekło rozpadnie się).

Dlaczego zdecydowano, że ograniczenia te nie będą częścią sygnatury metody dla CLR, to zupełnie inna kwestia, a ja mogłem tylko źle o tym przypuszczać. Pozwolę ludziom, którzy to wiedzą, odpowiedzieć na to pytanie.

+0

Ale to tylko przesuwa pytanie z "dlaczego nie jest częścią C#, dlaczego nie jest częścią CLR" ... Istnieje podstawowy problem z obsługą rozdzielczości przeciążenia, która uwzględnia ograniczenia typu (zobacz moją odpowiedź) . –

+0

Istnieje kilka funkcji w kilku językach .Net, które nie są implementowane przez inne. Najczęściej podaje się, że składnia pomocnicza może być trywialnie przekonwertowana na właściwą składnię. Jest to jedna z bardzo prostych, polegająca na prostym określeniu, która metoda wywołuje miejsce. Co więcej, nie jest to jedyny przypadek możliwej niejasności w języku i nie ma żadnego powodu, dla którego kompilator nie mógłby po prostu użyć tego, co znalazł lub podać błąd, jeśli nie może rozwiązać konkretnego wywołania metody, tak jak daje to w dziesiątkach innych sytuacjach. Funkcje językowe nie są funkcjami VM. –

0

Jeśli T pasuje do wielu wiązań, powstaje niejednoznaczność, która nie może być automatycznie rozstrzygnięta. Na przykład masz jedną klasę ogólną z przymusu

where T : IFirst

a drugi z przymusu

where T : ISecond

chcesz teraz T być klasa, która implementuje zarówno IFirst i ISecond.

konkretny przykład kod:

public interface IFirst 
{ 
    void F(); 
} 

public interface ISecond 
{ 
    void S(); 
} 

// Should the compiler pick this "overload"? 
public class My<T> where T : IFirst 
{ 
} 

// Or this one? 
public class My<T> where T : ISecond 
{ 
} 

public class Foo : IFirst, ISecond 
{ 
    public void Bar() 
    { 
     My<Foo> myFoo = new My<Foo>(); 
    } 

    public void F() { } 
    public void S() { } 
} 
+0

.. To powoduje kolizję nazw; w moim pytaniu błąd jest spowodowany przez kompilator nie wiedząc, którą metodę przejąć do pobrania dla wywołania metody: 'Bar (new Iguana(), null)'. Prawdopodobnie jestem powolny, ale nie widzę jeszcze połączenia między tymi dwoma. Zamierzam przestudiować twój przykład nieco bardziej .. – Daryl

+4

@EricJ możesz również wywołać dwuznaczność metody bez użycia generycznych - taka sama sytuacja miałaby miejsce, gdyby dwa przeciążenia metody zajęły odpowiednio "IFirst" i "ISecond", a ty próbowałeś aby rozstrzygnąć, która metoda wywołać z argumentem typu 'Foo'. Nie sądzę, że właśnie dlatego zespół C# postanowił nie być częścią sygnatury metody. –

+0

@ChrisShain Hmm, ale jeśli masz niejednoznaczność dla metody wywołania IFirst i ISecond, kompilator się nie powiedzie i możesz naprawić problem, przesyłając parametr do odpowiedniego interfejsu. Jeśli ogólne ograniczenia były częścią sygnatur metod, potrzebna byłaby składnia do wybrania między różnymi ograniczeniami w witrynie wywołania, a wszelkie zmiany ogólnych ograniczeń biblioteki oznaczałyby, że kod wywołujący musiałby zostać zrekompilowany, aby kontynuować działanie, co moim zdaniem jest mniejsze niż idealne . –

Powiązane problemy