Neden C # 'da yeni () bir kısıtlama var ama benzer bir kısıtlama yok?


19

C # jeneriklerinde, type parametresinin Tvarsayılan yapıcıya sahip olması için bir kısıtlama söyleyerek söyleyebiliriz where T : new(). Bununla birlikte, bunun gibi başka hiçbir kısıtlama geçerli değildir - new(string)örneğin, vb.

Bir dil tasarımı ve / veya uygulama bakış açısından, bunun nedeni nedir?

Yapıcıların çalışma biçiminde ya da bunu yasaklayan (ya da en azından zorlaştıran) tip sisteminin uygulanma biçiminde bir şey var mı? Eğer öyleyse, nedir? Ben bir yere okumaya hatırlıyorum default(T)aslında derler new T()için T : struct. Bununla ilgili mi belki?

Ya da dili çok karmaşık hale getirmekten kaçınmak için verilen bir tasarım kararı mı?


new(string)varsayılan bir yapıcı kısıtlaması değildir. Sorunuz "Neden belirli kurucu imzaları gerektiren kısıtlamalar yok?" Muhtemelen böyle bir kısıtlama özellikle yararlı olmaz.
Robert Harvey

3
@RobertHarvey Evet, tam olarak bunu söylüyorum. Aslında, varsayılan kurucuları özel uygulama açısından özel kılan bir şey olup olmadığını veya bunu eklemek için diğerini değil sadece keyfi bir seçim olup olmadığını soruyorum.
Theodoros Chatzigiannakis

Varsayılan kurucular belirli ve önemli yollarla faydalıdır. Örneğin, bir türü kolayca serileştirilebilir hale getirir.
Robert Harvey

6
Özel imzalı imzalar faydalı olabilir. Örneğin, yazım değişkeniniz bir T (Koleksiyon <T>) ctor ile Koleksiyon <T> ile kısıtlanmışsa, başka bir koleksiyon daha verdiğinizi bilirsiniz. Bununla birlikte, bu kullanışlılığın ekstra karmaşıklığa değip değmeyeceği bir sorudur.
Phoshi

Yanıtlar:


5

Yetkili bir cevap için, Eric Lippert'in birkaç yıl önce StackOverflow'daki bu soruya verdiği cevaba atıfta bulunacağım , bunun bir kısmı aşağıda kısaca alıntılanmıştır.

Ancak, bu özel durumda, dilin gelecekteki bir sürümü için olası bir özellik olarak bir tasarım toplantısında ortaya çıkarsa, özelliği geri çekmem için bazı nedenler verebilirim.

...

Tüm özelliği ya da hiç yapmamamız gerektiğini söylüyorum. Türleri belirli kuruculara sahip olacak şekilde kısıtlamak önemliyse, tüm özelliği yapalım ve türleri sadece kurucuları değil genel olarak üyeler temelinde kısıtlayalım.


2
Bağlamdan çıkarılan bu alıntı çok yanıltıcıdır. Eric'in Microsoft'un "sonuna kadar gitmesi gerektiğini" düşündüğünü gösteriyor ki bu onun pozisyonu değil. Aslında, önerilen özelliğe tam olarak karşıdır.
Robert Harvey

1
Teşekkürler, bu sorumu kısmen cevaplıyor: Eric Lippert, cevabının sonuna kadar bunun IL'nin bir sınırlaması olduğunu ve bu özelliğin dahil edilmesinin IL'ye eklenmesi gerektiğini belirtti. Eğer IL bölümü için oluşturulan ne bir kaynak olabilir eğer mükemmel olurdu edilir jenerik olarak varsayılan bir kurucu çağırmak, bir - uyguladı.
Theodoros Chatzigiannakis

@TheodorosChatzigiannakis: Neden Telerik'in Decompiler'ını ateşleyip kendin bulmuyorsun?
Robert Harvey

2
@RobertHarvey Onun için bir pozisyon önermediğini düşünmüyorum, ama pozisyonunu vurgulamak için ek bir teklif ekledim.
Chris Hannon

1
Hmm, F #, bir sınıfın işleci olup olmadığını derleme zamanı olarak kontrol etmek gibi bir türü kısıtlamak için daha gelişmiş yollara sahiptir. Belki de, F #, çok katı tip kontrolü nedeniyle C # 'dan daha güçlü bir kısıtlama sistemine ihtiyaç duyar. Bununla birlikte, bu dil .Net Framework üzerinde sınıf tutmanın gelişmiş yollarını uygulayabilir.
OnesimusUnbound

16

Ayrıştırmak (Robert Harvey'nin önerisine göre) ilgilenen herkes için aşağıdakileri sağladı. Bu method:

static T GenericMake<T>()
    where T : new()
{
    return new T();
}

Görünüşe göre, derlendiğinde şu olur:

private static T GenericMake<T>()
    where T : new()
{
    T t;
    T t1 = default(T);
    if (t1 == null)
    {
        t = Activator.CreateInstance<T>();
    }
    else
    {
        t1 = default(T);
        t = t1;
    }
    return t;
}
  • Eğer Tbir değer türüdür new()olur default(T).
  • Eğer Tbir referans türüdür new()yansıma kullanarak çalışır. Activator.CreateInstance()dahili aramalar RuntimeType.CreateInstanceDefaultCtor().

Yani - dahili olarak, varsayılan kurucular CLR ile ilgili olarak C # için gerçekten özeldir. Jeneriklerde daha karmaşık kısıtlamalar için bazı geçerli kullanım durumları olsa bile, diğer kuruculara aynı tedaviyi vermek maliyetli olurdu.


4
İlginç. default(T) Değer türleri için neden yinelenen çağrı ?
Avner Shahar-Kashtan

2
@ AvnerShahar-Kashtan Bilmiyorum. tDeğişken gibi derleme / ayrıştırma işleminin bir artefaktı olabilir (iç içe returnifadelerle değiştirilebilir ).
Theodoros Chatzigiannakis
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.