2013-07-18 12 views
13

Zgodnie z odpowiedzią this na stackoverflow, typ ogólny w języku C# jest rozwiązany w środowisku wykonawczym.Kiedy jest typ ogólny rozwiązany w języku C#?

Jednak zgodnie z odpowiedzią this, w języku C# typ ogólny to rozwiązany w czasie kompilacji.

Czego mi tu brakuje?

Innymi słowy, czy typ T został rozwiązany podczas kompilacji lub uruchamiania?

Aktualizacja:

podstawie odpowiedzi Oded, w W przypadku takim jak ten, gdzie typ jest zamknięty typu beton (co oznacza, że ​​będzie rozwiązany w czasie kompilacji)

class Program 
{ 
    static void Main() 
    { 
     var t = new Test<int>(); 
    } 
} 

public class Test<T> 
{ 
} 

będzie MSIL ma odpowiednik

+3

Te dwa posty, do których linkujesz, opisują różne koncepcje. – JerKimball

+2

Jaką część tego z wysłanej odpowiedzi w podanym przez ciebie linku nie rozumiesz: "Nie; to jest zasadniczo niemożliwe. Głównym celem generics jest tworzenie typów kompilacji. Próbujesz utworzyć typ nieznany w czasie kompilacji. Możesz to zrobić za pomocą refleksji. (typeof (MyClass <>). MakeGenericType (myType)) ' – MethodMan

+0

Zgaduję, że szukasz' How to do Reflection' Przykład – MethodMan

Odpowiedz

21

Problem polega na tym, że pytanie nie jest dobrze postawione. Dwie osoby twierdzą, że są przeciwne: typy są "rozwiązywane" w czasie wykonywania, a typy są "rozwiązywane" w czasie kompilacji.

Ponieważ są one sprzeczne, muszą oznaczać coś innego przez "rozwiązany".

Nie wiem, co to znaczy, że typ zostanie "rozwiązany". Wiem jednak, jaka jest rozdzielczość przeciążania . Pytany, aby rozwiązać przeciążeniem rozdzielczości problem, który nie wiąże dynamic, kompilator C# określa, które przeciążać zadzwonić w czasie kompilacji, na podstawie informacji o czasie kompilacji o typach generycznych. Tak na przykład, jeśli masz:

static void Main() 
{ 
    var d = new D(); 
    var p = new P<D>(); 
    p.N(d);//Displays In class B 
} 


class B 
{ 
    public void M()// Note, not virtual 
    { 
     Console.WriteLine("In class B"); 
    } 
} 

class D : B 
{ 
    public new void M()// new, not overload 
    { 
     Console.WriteLine("In class D"); 
    } 
} 

class P<T> where T : B 
{ 
    public void N(T t) 
    { 
     t.M(); 
    } 
} 

N zawsze wywołuje B.Mnawet jeśli P<T> jest tworzony jako P<D>. Czemu? Ponieważ rozwiązanie problemu przeciążenia, który określa, jakie znaczenie t.M jest musi być rozwiązany gdy P<T>.N jest kompilowany, a w tym czasie najlepszy kompilator wie, że musi być Bt, więc wybiera B.M.

Jeśli to nie jest to, co masz na myśli przez "rozwiązany", wtedy wyjaśnij pytanie.

+0

Czy Twój przykład pokazuje rozdzielczość przeciążenia lub wiązanie? O ile bindowanie wymaga rozdzielczości przeciążeniowej, to jedyne dwie metody o nazwie "M" mają identyczne podpisy, więc "rozdzielczość przeciążania" będzie miała tylko jednego kandydata do pracy. Myślę, że lepszym przykładem dla "rozdzielczości przeciążenia" może być 'static bool Porównaj (T p1, T p2) gdzie T: class {return p1 == p2;} ... Compare (" 5 ", 5.ToString()) '. Skoro kompilator nie może wiedzieć, że 'T' będzie typu' String', to nie może wiedzieć, że powinien używać przeciążenia 'String'-vs -String'' == 'zamiast porównywania porównawczego? – supercat

+0

BTW, jest porównawczym porównaniem '==' przeciążenia, czy jest to inny rodzaj magii kompilatora? Przeciążenie '==', które przyjęło parametry typu 'Obiekt', umożliwiłoby porównanie dwóch typów, ale operator C#' == 'nie działa w ten sposób. Jego zachowanie wydaje się zupełnie inne od wszystkiego, co można osiągnąć poprzez normalną rozdzielczość przeciążania. – supercat

+0

@supercat: Dobre pytanie. W rzeczywistości wykorzystuje normalną rozdzielczość przeciążania operatora z niewielkimi modyfikacjami. Po pierwsze, wyrażenia w postaci 'x == null',' null! = X' i tak dalej są traktowane specjalnie. Następnie rozdzielczość przeciążania odbywa się normalnie. Następnie następuje etap weryfikacji po rozwiązaniu. Jeśli rozdzielczość przeciążenia wybierze operator 'object == object', a jeden lub oba operandy nie będą miały typu odniesienia, to zostanie wywołany warunek błędu. (Ten krótki szkic nie opisuje wszystkich subtelności, zobacz specyfikację dla szczegółów.) –

12

Brakuje ci koncepcji open and closed generic types.

Zasadniczo, zamknięty rodzaj ogólny występuje wtedy, gdy faktycznie określa się istniejące typy w parametrach ogólnych (lub są one wnioskowane przez kompilator). Np

Nullable<int> nulInt; 

typu otwartego rodzajowe, w której jedna lub więcej ogólny typ ma być określona w czasie pracy (tak, klasa Nullable<T> jest przykładem).

+0

Ah, durn it - pobiłeś mnie do tego. :) – JerKimball

1
  1. pierwsza odpowiedź jest o metodę Parametry
  2. a druga jest o ogólnych parametrów typu

to co tracisz.

Dokładniej: 1. C# jest domyślnie wpisane statycznie, więc podczas przekazywania parametrów otrzymasz najlepszy typ dopasowania i metodę. (Sprawdź także odpowiedź na temat "dynamicznych" parametrów.) 2. Ustawienie ogólnego parametru typu przez składnię C# dotyczy typów statycznych. Ustawienie go za pomocą refleksji dotyczy czegoś innego.

coś innego: „.NET” każdy typ ma fazę inicjalizacji w jego pierwszym użyciem w czasie wykonywania. (Patrz pola statyczne i konstruktor statyczny)

tak: Wszystkie typy zainicjowany w czasie wykonywania, ale wykorzystywane są typy statyczne (lub dynamiczny ...) w czasie kompilacji, który jest, kiedy trzeba być "rozwiązany ".

1

Typy otwarte (myclass<T>) nie istnieją w czasie wykonywania. Ale typy niezwiązane mogą istnieć w czasie wykonywania (myclass<>). Aby rozwiązać typ niezwiązany w środowisku wykonawczym, należy użyć operatora typeof.

Innymi słowy, jeśli nie jest używany operator typeof, typy ogólne są zamykane podczas kompilacji.

Powiązane problemy