W przedstawionym poniżej przykładowym kodzie metoda "CompileError" nie będzie kompilować, ponieważ wymaga ograniczenia where T : new()
, jak pokazano w metodzie CreateWithNew()
. Jednak metoda CreateWithActivator<T>()
kompiluje się dobrze bez ograniczeń.Dlaczego funkcja Activator.CreateInstance <T>() jest dozwolona bez ograniczenia typu nowego()?
public class GenericTests
{
public T CompileError<T>() // compile error CS0304
{
return new T();
}
public T CreateWithNew<T>() where T : new() // builds ok
{
return new T();
}
public T CreateWithActivator<T>() // builds ok
{
return Activator.CreateInstance<T>();
}
}
Dlaczego tak jest?
Według https://stackoverflow.com/a/1649108/531971, która odwołuje MSDN documentation i this question wyrażenie w rodzajowych new T()
jest rzeczywiście realizowane użyciu Activator.CreateInstance<T>()
. Tak więc nie rozumiem, dlaczego wywołanie new T()
wymaga, aby typ ogólny był ograniczony w sposób, który można pominąć podczas korzystania z Activator.CreateInstance<T>()
.
Lub, aby postawić pytanie na odwrót: jaki jest sens ograniczenia where T : new()
, jeśli łatwo utworzyć instancje T
w metodzie ogólnej bez ograniczenia, bezpośrednio używając dokładnie tej samej infrastruktury bazowej?
Ponieważ 'CreateInstance()' po prostu używa zwykłego starego odbicia i nie podlega żadnym ograniczeniom. Jeśli typ ma domyślny konstruktor, utworzy go. –
To jest samokontrola. Możesz zrobić prawie wszystko poprzez refleksję (nawet zniszczyć wszystkie zasady OOP), ale wielu tego nie doceni, bo jest brudna. – eocron
Istnieje wiele sposobów pisania niezręcznego kodu, który pozwala wyeliminować błąd czasu kompilacji i wygenerować zamiast niego środowisko wykonawcze. To tylko jedna instancja. Na przykład. 'dynamic' umożliwia pisanie wywołań do funkcji, które nie istnieją, więc zamiast błędu kompilatora pojawia się wyjątek środowiska wykonawczego. Podobnie, tutaj "CreateInstance" pozwala odłożyć, że nie istnieje konstruktor bez parametrów do czasu wykonania. –