C # Generics'te "varsayılan" tür parametrelere makul bir yaklaşım var mı?


93

C ++ şablonlarında, belirli bir tür parametresinin varsayılan olduğu belirtilebilir. Yani, açıkça belirtilmedikçe, T tipini kullanacaktır.

Bu C # ile yapılabilir veya yaklaştırılabilir mi?

Şunun gibi bir şey arıyorum:

public class MyTemplate<T1, T2=string> {}

Böylece, açıkça belirtmeyen türden bir örnek T2:

MyTemplate<int> t = new MyTemplate<int>();

Esasen şunlar olabilir:

MyTemplate<int, string> t = new MyTemplate<int, string>();

Nihayetinde oldukça yaygın olarak kullanılan bir şablonun olduğu bir duruma bakıyorum, ancak ek bir tür parametresi ile genişletmeyi düşünüyorum. Sanırım alt sınıf yapabilirim, ama bu damarda başka seçenekler olup olmadığını merak ediyordum.

Yanıtlar:


77

Alt sınıflandırma en iyi seçenektir.

Ana genel sınıfınızı alt sınıflara ayırırdım:

class BaseGeneric<T,U>

belirli bir sınıfla

class MyGeneric<T> : BaseGeneric<T, string>

Bu, mantığınızı tek bir yerde (temel sınıf) tutmanızı ve aynı zamanda her iki kullanım seçeneğini de sağlamanızı kolaylaştırır. Sınıfa bağlı olarak, bunun gerçekleşmesi için muhtemelen çok az ekstra çalışma gerekir.


1
ah ... bu mantıklı. Tür parametreleri benzersiz bir imza sağlıyorsa, tür adının aynı olmasına izin verilir mi?
el2iot2

2
@ee: evet, jenerikler overloadableparametre sayısına göredir .
Mehrdad Afshari

@ee: Evet, ama bunu yapmaktan çekinirim. .NET'te bunu yapmak "yasal" dır, ancak kafa karışıklığına neden olabilir. Dizeden türetilmiş türün adının ana genel sınıfa benzer olmasını tercih ederim (bu nedenle ne olduğu açık / bulunması kolay), ancak bunun bir dizge olduğunu açıkça gösteren bir ad.
Reed Copsey

@Reed: Gerçekten kafa karışıklığına yol açıyor mu? Bu özel durum için, aynı isme sahip olmanın bile yardımcı olduğunu düşünüyorum. .NET'te aynı şeyi yapan örnekler vardır: Örneğin Func <> delege.
Mehrdad Afshari

4
Örneğin, Predicate <T> yalnızca Func <T, bool> 'dur, ancak farklı bir amaç için olduğu için yeniden adlandırıldı.
Reed Copsey

19

Çözümlerden biri alt sınıflamadır. Bunun yerine kullanacağım bir diğer yöntem fabrika yöntemleridir (var anahtar sözcüğü ile birlikte).

public class MyTemplate<T1,T2>
{
     public MyTemplate(..args..) { ... } // constructor
}

public static class MyTemplate{

     public static MyTemplate<T1,T2> Create<T1,T2>(..args..)
     {
         return new MyTemplate<T1, T2>(... params ...);
     }

     public static MyTemplate<T1, string> Create<T1>(...args...)
     {
         return new MyTemplate<T1, string>(... params ...);
     }
}

var val1 = MyTemplate.Create<int,decimal>();
var val2 = MyTemplate.Create<int>();

Yukarıdaki örnekte val2tiptedir MyTemplate<int,string> ve ondan türetilen bir tip değildir .

Bir tür class MyStringTemplate<T>:MyTemplate<T,string>, ile aynı türde değildir MyTemplate<T,string>. Bu, belirli senaryolarda bazı sorunlar yaratabilir. Örneğin siz bir örneğini döküm olamaz MyTemplate<T,string>için MyStringTemplate<T>.


3
Bu en kullanışlı yaklaşımdır. Çok güzel çözüm
T-moty 04

12

bunun gibi bir sınıf Aşırı Yüklemesi de oluşturabilirsiniz.

public class MyTemplate<T1, T2> {
    public T1 Prop1 { get; set; }
    public T2 Prop2 { get; set; }
}

public class MyTemplate<T1> : MyTemplate<T1, string>{}

Lütfen geç yanıt göndermeden önce diğer yanıtları okuyun, çünkü muhtemelen çözümünüz diğerleriyle aynıdır.
Cheng Chen

7
kabul edilen cevap, farklı bir adla bir sınıf oluşturmaktı, benim çözümüm aynı sınıfı
aşırı yüklemek

2
Hayır, ikisi de yeni bir sınıf oluşturuyor. İsim burada önemli değil. MyTemplate<T1>farklı bir sınıftır MyTemplate<T1, T2>ne, AnotherTemplate<T1>.
Cheng Chen

7
Gerçek türler farklı olsa bile, ki bu açık ve doğru, aynı adı kullanırsanız kodlama daha kolay. Sınıf "aşırı yüklemesinin" bu şekilde kullanılabileceği herkes için açık değildir. @DannyChen haklı - teknik açıdan sonuçlar aynı, ancak bu yanıt OP'nin istediğini elde etmeye daha yakın.
Kuba

1
Ne yazık ki, bu çözüm hala gerçek "varsayılan" genel argümanlardan daha düşüktür, çünkü a MyTemplate<T1, string>atanamaz MyTemplate<T1>, bu arzu edilebilir
Felk

10

C # böyle bir özelliği desteklemez.

Dediğin gibi, alt sınıflara ayırabilirsin (eğer mühürlenmemişse ve tüm yapıcı bildirimlerini çoğaltabilirsin) ama bu tamamen farklı bir şey.


3

Maalesef C # yapmaya çalıştığınız şeyi desteklemiyor. Bir parametrenin varsayılan türünün genel kısıtlamalara uyması gerektiği ve CLR tip güvenliğini sağlamaya çalıştığında büyük olasılıkla baş ağrısı yaratacağı düşünüldüğünde, uygulanması zor bir özellik olacaktır.


1
Pek sayılmaz. Bir öznitelikle (VB.NET'teki varsayılan parametreler gibi) yapılabilir ve derleyicinin onu derleme zamanında değiştirmesini sağlayabilir. Birincil neden C # tasarım hedefleridir.
Mehrdad Afshari

Derleyici, varsayılan parametrenin genel kısıtlamaları karşıladığından emin olmalıdır. Ayrıca, yöntemdeki tür parametresi hakkında yapılan herhangi bir varsayım, varsayılan olmayan herhangi bir tür parametresinin ondan miras almasını gerektireceğinden, varsayılan parametrenin kendisi bir genel kısıtlama olacaktır.
Andrew Hare

@Andrew, varsayılan parametrenin genel bir kısıtlama olması gerekmez. Bu, C ++ 'daki varsayılan şablon parametreleri gibi davranacak olsaydı, o zaman automatonic sınıfını genişletmek mükemmel olurdu: MyTemplate <int, float> x = null T2 genel kısıtlamalarına sahip olmadığından, varsayılan string türüne rağmen float iyidir . Bu şekilde, varsayılan şablon parametreleri, MyTemplate <int> 'yi MyTemplate <int, string> için kısaltma olarak yazmak için esasen "sözdizimsel şeker" dir.
Tyler Laing

@Andrew, C # derleyicisinin bu tür varsayılan şablon parametrelerinin mevcut genel sabitleri karşıladığını doğrulaması gerektiğini kabul ediyorum. C # derleyicisi, sınıf bildirimlerinde benzer bir şeyi zaten doğrular, örneğin Reed'in BaseGeneric <T, U> sınıfına "where U: ISomeInterface" gibi genel bir kısıtlama ekleyin ve ardından MyGeneric <T> bir hata ile derleme yapamaz. Varsayılan bir şablon parametresinin doğrulanması hemen hemen aynı olacaktır: derleyici, bir sınıfın bildirimini doğrular ve hata mesajı aynı veya çok benzer olabilir.
Tyler Laing

"Uygulanması zor bir özellik olurdu" Bu çok saçma. Uygulanması önemsiz olurdu. Bir türü şablon kısıtlamalarına göre doğrulama işi zorlaşmaz çünkü aday tür dosyada farklı bir yerde görünür (yani şablon somutlaştırmada değil, şablonda).
Çamur
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.