2013-08-08 10 views
10

Tutaj mamy prostą klasę herarchy i korzystanie z leków generycznych z type constraint od new()Generic typu ograniczenie nowych() i abstrakcyjnym bazowej klasy

public abstract class Base 
{ 
} 

public class Derived : Base 
{ 
} 

public class TestClass 
{ 
    private void DoSomething<T>(T arg) where T : new() 
    { 
    } 

    public void TestMethod() 
    { 
     Derived d1 = new Derived(); 
     DoSomething(d1); // compiles 

     Base d2 = new Derived(); 
     DoSomething(d2); // compile error 
    } 
} 

kod nie skompilować na wskazanej linii, z błąd z:

„bazy” musi być non-abstrakcyjny typ z publicznego konstruktora bez parametrów w celu wykorzystania go jako parametr „T” w ogólnym typie lub metodzie „Foo.DoSomething (T)”

Ten błąd jest jasny i ma sens, ale miałem nadzieję, że kompilator zrozumie, że wszystkie wyprowadzenia z Base (które mogą być tworzone w tym momencie) mają publiczny konstruktor bez parametrów.

Czy teoretycznie jest to możliwe dla kompilatora?

+0

Ta linia martwi mnie bardziej o "typ nie abstrakcyjny" niż klauzula konstruktora bez parametrów. –

Odpowiedz

8

Niestety trzeba wyraźnie dać rodzaju

DoSomething<Derived>(d2); 

teoretycznie nie jest możliwe, aby stworzyć coś, co jest abstrakcyjny

+5

Podoba mi się część "teoretycznie". Sprawia, że ​​czuję się, jakby Jon Skeet wpadł, zrobił trochę magii, a ty masz instancję abstrakcyjnego obiektu. –

+0

W której wersji .NET kompiluje się, jeśli d2 jest deklarowane jako abstrakcyjna baza? –

1

new Constraint (C# Reference):

Aby korzystać z nowego ograniczenia, typu nie może być abstrakcyjny.

Wywołanie:

Base d2 = new Derived(); 
DoSomething(d2); 

Jesteś w rzeczywistości robi:

Base d2 = new Derived(); 
DoSomething<Base>(d2); 

Ponieważ Base jest abstrakcyjny, pojawia się błąd kompilacji.

Tak, masz do oddania wyraźnie:

Base d2 = new Derived(); 
DoSomething((Derived) d2); 

Jak można zapewnić kompilator, że ktokolwiek tam umieścić coś, co nie jest streszczenie?

Jedyny sposób, jaki widzę, to jeśli otrzymamy słowo kluczowe typu "must-inherit-to-non-astract", a następnie stworzymy public must-inherit-to-non-abstract abstract class Base. Następnie kompilator może być pewien, że jeśli umieścisz instancję podstawową w swojej metodzie, będzie to w rzeczywistości podklasa, która nie będzie abstrakcyjna i dlatego może być utworzona.