2009-04-01 18 views
65

W szablonach C++ można określić, że określony parametr jest domyślny. To znaczy. chyba że jest to wyraźnie określone, użyje on typu T.Czy istnieje rozsądne podejście do "domyślnych" parametrów typu w C# Generics?

Czy można to zrobić w przybliżeniu w C#?

szukam czegoś podobnego:

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

Tak, że wystąpienie typu, który nie precyzuje T2:

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

Byłoby zasadniczo:

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

Ostatecznie szukam przypadku, w którym istnieje szablon, który jest dość szeroko sed, ale rozważam rozszerzenie z dodatkowym parametrem typu. Mógłbym się podklasować, ale byłem ciekawy, czy w tym żyły były inne opcje.

Odpowiedz

61

Podklasy to najlepsza opcja.

Chciałbym podklasy głównego klasy Generic:

class BaseGeneric<T,U>

z określonej klasy

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

To sprawia, że ​​łatwo utrzymać swoją logikę w jednym miejscu (klasa bazowa) , ale również łatwe do zapewnienia obu opcji użytkowania. W zależności od klasy prawdopodobnie do tego nie potrzeba dodatkowej pracy.

+1

Ach ... to ma sens.Czy nazwa typu może być taka sama, jeśli parametry typu zapewniają unikalny podpis? – el2iot2

+2

@ee: tak, generics są "przeciążane" przez liczbę parametrów. –

+0

@ee: Tak, ale bym się tym obawiał. Jest to "legalne" w .NET, aby to zrobić, ale może prowadzić do zamieszania. Wolałbym, aby nazwa typu pochodnego napisu była podobna do głównej klasy ogólnej (więc jest oczywiste, co to jest/łatwo znaleźć), ale nazwa, która czyni oczywistym, że jest ciągiem znaków. –

6

C# nie obsługuje takiej funkcji.

Tak jak powiedziałeś, możesz ją podklasować (jeśli nie jest zapieczętowana i zduplikować wszystkie deklaracje konstruktorów), ale jest to zupełnie inna sprawa.

1

Niestety C# nie obsługuje tego, co próbujesz zrobić. Wdrożenie tej funkcji byłoby trudne, ponieważ domyślny typ parametru musiałby być zgodny z ogólnymi ograniczeniami i najprawdopodobniej wywoływałby bóle głowy, gdy CLR próbował zapewnić bezpieczeństwo typu.

+1

Niezupełnie. Mogło to zostać wykonane za pomocą atrybutu (np. Parametrów domyślnych w VB.NET) i mieć go zastąpić kompilator podczas kompilacji. Głównym powodem są cele projektowe C#. –

+0

Kompilator musi zapewnić, że parametr domyślny spełnia ogólne ograniczenia. Ponadto domyślnym parametrem byłoby samo ograniczenie ogólne, ponieważ wszelkie założenia dotyczące parametru typu w metodzie wymagałyby dziedziczenia z niego dowolnego innego typu parametru. –

+0

@Andrew, domyślny parametr nie musi być ogólnym ograniczeniem. Gdyby to było zachowywać się bardziej jak domyślnymi parametrami szablonu w C++ następnie rozszerzenie na klasę automatonic za to byłoby perfekcyjnie Do: MyTemplate x = null Ponieważ T2 nie ma ogólnych ograniczeń, więc pływak jest w porządku, mimo domyślnego typu string . W ten sposób domyślne parametry szablonu są w zasadzie "syntaktycznym cukrem" do pisania MyTemplate jako skrót do MyTemplate . –

13

Jednym z rozwiązań jest podklasowanie. Innym, którego użyłbym zamiast tego, jest metoda fabryczna (w połączeniu ze słowem kluczowym var).

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

W powyższym przykładzie val2 jest typu MyTemplate<int,string>nie typu pochodzą od niego.

Typ class MyStringTemplate<T>:MyTemplate<T,string> nie jest tego samego typu co MyTemplate<T,string>. Może to powodować pewne problemy w niektórych scenariuszach. Na przykład nie można rzucić wystąpienia z MyTemplate<T,string> na MyStringTemplate<T>.

+3

Jest to najbardziej użyteczne podejście. Bardzo ładne rozwiązanie –

8

można również utworzyć klasę Przeciążenie Podobnie jak

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

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

Proszę przeczytać inne odpowiedzi, zanim napiszesz późną odpowiedź, ponieważ prawdopodobnie twoje rozwiązanie jest takie samo jak inne. –

+4

zaakceptowaną odpowiedzią było utworzenie klasy o innej nazwie, moim rozwiązaniem jest przeciążenie tej samej klasy. – Moes

+1

Nie, obie tworzą nową klasę. Imię nie ma tutaj znaczenia. 'MyTemplate ' jest inną klasą od 'MyTemplate ', ani 'AnotherTemplate '. –