2016-09-12 33 views
10

Aşağıda gösterilen örnek kodda, "CompileError" yöntemi derlenmeyecektir, çünkü CreateWithNew() yönteminde gösterildiği gibi where T : new() kısıtlaması gerektirir. Bununla birlikte, CreateWithActivator<T>() yöntemi, bir kısıtlama olmaksızın yalnızca iyi derler.Neden activator.CreateInstance <T>() yeni() jenerik tür kısıtlaması olmadan izin verilir?

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>(); 
    } 
} 

Neden?

MSDN documentation başvuran https://stackoverflow.com/a/1649108/531971 göre

ve this question, jenerik new T() sentezleme aslında Activator.CreateInstance<T>() kullanılarak uygulamıştır. Bu yüzden, neden new T() numaralı telefonun aranmasının, jenerik türün Activator.CreateInstance<T>() kullanıldığında atlanabilecek şekilde kısıtlanmasını gerektirdiğini anlamıyorum.

Veya tersi soru koymak; doğrudan tam aynı temel altyapısını kullanarak, kısıtlama olmaksızın genel bir yöntemde T örneklerini oluşturmak kolaydır eğer where T : new() kısıtlama noktası ne?

+1

Çünkü CreateInstance() 'sadece düz eski yansımayı kullanır ve herhangi bir kısıtlamaya tabi değildir. Türün varsayılan kurucusu varsa, bunu oluşturacaktır. –

+1

Bu, kendi kendini kontrol eden bir şeydir. Yansıma yoluyla her şeyi yapabilirsiniz (tüm OOP prensiplerini bile yok edin), fakat çoğu bunu takdir etmez, kirlenmesine neden olur. – eocron

+2

Bir derleme zamanı hatasını ortadan kaldırmanıza ve bunun yerine çalışma zamanı oluşturmanıza olanak tanıyan garip kod yazmanın birçok yolu vardır. Bu sadece bir örnek. Örneğin. '' dinamik', mevcut olmayan fonksiyonlara çağrı yazmanıza izin verir, bu yüzden derleyici hatası yerine çalışma zamanı istisnası alırsınız. Aynı şekilde, burada, "CreateInstance", çalışma zamanına kadar parametresiz bir kurucunun bulunmadığını öğrenmeyi ertelemenize izin verir. –

cevap

12

Activator ve T() arasında kavramsal bir fark vardır:

  • Activator.CreateInstance<T> - Ve birini yoksa bir Exception atmak - Ben varsayılan kurucuyu kullanarak T yeni bir örneğini oluşturmak istiyorum (Çok yanlış bir şey olduğu ve bunu hallettiğim/attığım için).

    • Yan not:as MSDN says unutmayın: tip derleme zamanında bilinmelidir çünkü Genelde

      , uygulama kodunda CreateInstance<T>() jenerik yöntem için hiçbir faydası yoktur. Tür derleme zamanında biliniyorsa, normal örnekleme sözdizimi kullanılabilir. Type derleme zamanında bilindiği zaman genellikle bir kurucu kullanabilirsiniz isteyeyim beri

      ( yavaş CreateInstance<T>()uses RuntimeTypeHandle.CreateInstance olan [Activator.CreateInstance<T> kendisi sınırlaması gerekmez yüzden de budur]).

  • T() - Ben sözde bir standart yapıcı çağrısı gibi, T boş kurucusunu çağırmak ister.

Sen nedenle derleyici bir olduğunu sınırlamak için istiyor "Böyle yapıcı bulunamadı" çünkü "standart" yapıcı çağrı başarısız istemiyoruz.Bundan daha fazlası; Exceptions üzerinden üzerinden Derleme zaman hatalarını tercih etmelisiniz.

T() ortalama durum için alakasız yansıma kullanarak dahili olarak uygulanan gerçeği "Ben sadece varsayılan örneği istiyoruz T" (Performansta veriyorsan iç uygulama önemlidir elbette/vb ...).

2

Bu sadece şekerdir. Kendini kontrol edebilen şeker varsa. Örneğin, herhangi bir türdeki herhangi bir yöntemle (örneğin, bazı durumlarda bile) yansıma aracılığıyla çağrı yapabilirsiniz, ancak bu doğru değil, kabul etmiyor musunuz? Kodunuz bir noktada henüz ulaşılamaz hale gelecektir ve yürütme süresinde birçok hata ortaya çıkacaktır, bu çok kötü. Yani, kendini infazdan önce kontrol edebilecek olursan, sadece yap.

Kısıtlama, derleme zamanında anlamanıza yardımcı olacaktır.

1

Activator.CreateInstance<T>() yöntem genel bir sınıf farklı şekillerde kullanılabilir olabilir lamak için kullanıcı kodu maruz, bazıları tür parametresinin belirli kısıtlamaları karşılamak ve bunlardan bazılarının yok olduğunu gerektirecektir. Örneğin, bir sınıf Foo<T> aşağıdaki kullanım alışkanlıklarına herhangi destekleyebilir:

  1. Müşteri kodu, yeni bir T döndüren bir işlev sağlamaktadır.

  2. İstemci kodu, varsayılan yapıcısını kullanarak yeni bir T oluşturan bir varsayılan işleve dönüşür.

  3. İstemci kodu, sınıfın herhangi bir özelliğini kullanarak, T'un yeni örneklerini oluşturmasını gerektirmez. 2. Yalnızca parametresiz kurucular sahip olan türleri ile çalışır iken

Grafikleri # 1 ve # 3, herhangi bir T ile kullanılabilir olmalıdır. Activator.CreateInstance<T>(), kısıtsız bir T için derlenip, parametresiz yapıcılara sahip olan T türleri için çalışır ve kod kullanımının üç kullanım modelini kolaylaştırır. Activator.CreateInstance<T>, new kısıtlamasına sahip olsaydı, bir tane olmayan genel tür parametreleriyle kullanmak çok zor olurdu.