2013-01-17 24 views
10

W jaki sposób można wprowadzić wzór enum bezpieczny dla klasy ogólnej? Załóżmy, że jest to realizowane wzdłuż tych liniiWpisz bezpieczną implementację wzorca enum z rodzajami głównymi

public class KnownSetting<T> 
{ 
    public readonly static KnownSetting<String> Name = new KnownSetting<String>("name", "Default Name", t => t); 
    public readonly static KnownSetting<int> Size = new KnownSetting<String>("size", "25", t => Converter.ToInt32); 

    public String Key { get; set; } 
    public T DefaultValue { get; set; } 
    public Func<String, T> Converter { get; set; } 

    private KnownSetting(String key, T defaultValue, Func<String, T> converter) 
    { 
     Key = key; 
     DefaultValue = defaultValue; 
     Converter = converter; 
    } 
} 

Realizacja wzór jest poprawny w ten sposób, ponieważ konstruktor pozostaje prywatny, ale podczas korzystania z tego konstruktu, wygląda źle:

public static class Program 
{ 
    public static void main() 
    { 
     var x = KnownSetting<?>.Name; 
    } 
} 

Wtedy rozwiązaniem byłoby należy podzielić go na dwie klasy: KnownSetting i Setting, ale wtedy zakres konstruktora nie może być prywatny, aby można go było utworzyć z poziomu kontenera.

W jaki sposób można zaimplementować ten wzorzec, aby jego ogólny aspekt pozostawał ukryty przed użytkownikiem końcowym, ale nadal jest silnie typowany? Czy istnieje bardziej odpowiedni wzór, czy jest lepszy sposób na jego wdrożenie?

Aktualizacja Dodałem drugą próbkę, aby zilustrować, że chcę, aby typ ustawienia był ogólny.

+4

swoje pole statyczne posiada osobne wartości dla każdego 'T'. Nie chcesz tego. – SLaks

+0

Najlepsze, co mogę zrobić, to zbudować wewnętrzny konstruktor i pójść z ideą "klasy kontenerowej", wtedy musisz polegać tylko na dyscyplinie programistów w ramach tego samego zespołu. –

+0

@SLaks Dlaczego nie chciałbym tego? – Spooles

Odpowiedz

4

Utwórz metodę pomocniczą w typie bazowym, która używa innego typu i utwórz znaną klasę ustawień. Potrzebujesz metody Create, ponieważ konstruktorem podstawowym jest Setting (string, object, Func). To także dlatego wprowadzam kolejną zmienną rodzajowe (U):

public class KnownSetting : Setting<object> 
{ 
    private KnownSetting(string key, object defaultValue, Func<string, object> converter) : base(key, defaultValue, converter) { } 

    public readonly static Setting<string> Name = Create<string>("name", "Default Name", t => t); 
    public readonly static Setting<int> Size = Create<int>("size", 25, t => Convert.ToInt32(t)); 
} 

public class Setting<T> 
{ 
    public string Key { get; set; } 
    public T DefaultValue { get; set; } 
    public Func<string, T> Converter { get; set; } 

    protected static Setting<U> Create<U>(string key, U defaultValue, Func<string, U> converter) 
    { 
     return new Setting<U>(key, defaultValue, converter); 
    } 

    protected Setting(string key, T defaultValue, Func<string, T> converter) 
    { 
     Key = key; 
     DefaultValue = defaultValue; 
     Converter = converter; 
    } 
} 
public static class Program 
{ 
    static void Main(string[] args) 
    { 
     var x = KnownSetting.Name; 
    } 
} 
+0

Jak to pomaga? Predefiniowany ma prywatnego ctor, ale nieużywany. W tym miejscu brakuje podstawowego i prywatnego ctora, które stanowi rdzeń problemu. – Spooles

+0

Masz rację, źle zrozumiałem problem. Zmieniłem moje rozwiązanie, aby odzwierciedlić problem; to powinna być odpowiedź, której szuka. – atlaste

+0

Jeśli chroniony Tworzenie, dlaczego nie ma prywatnej konstruktor? – Spooles

3

stwierdzenie danych statycznych w nowej klasie:

public class KnownSetting 
{ 
    public readonly static KnownSetting<String> Name = new KnownSetting<String>("name", "Default Name", t => t); 
    public readonly static KnownSetting<int> Size = new KnownSetting<String>("size", "25", t => Converter.ToInt32); 
} 

To może mieć taką samą nazwę w języku C#, ponieważ nazwy klas są unikalne na nazwę rodzajową powiększonej liczby typu argumentów.

+1

Dodatkowo, możesz mieć 'KnownSetting ' dziedziczący po 'KnownSetting', więc istnieje" rodzajowy "niepisany formularz, który możesz zgrupować razem, jeśli to konieczne. – Bobson

+0

Ale konstruktor 'KnownSetting ' musi publicznie, aby to działało. –

+0

@ default.kramer dobry punkt. Może być jednak wewnętrzny. – usr

0

Może ja czegoś brakuje, ale dlaczego nie wystarczy użyć klasy KnownSetting<T> jak jest, i poznać nowych odniesień do tych samych instancji enum od nowa klasa? Coś jak:

public static class KnownSettings { 
    public readonly static KnownSetting<string> Name = KnownSetting<string>.Name; 
    public readonly static KnownSetting<int> Size = KnownSetting<int>.Size; 
    // etc. 
} 

Następnie można użyć wartości zgodnie z potrzebami:

var x = KnownSettings.Name; 
+0

Ponieważ KnownSetting i KnownSetting (bez generics) nie jest tą samą klasą, więc non-genic nie może zobaczyć prywatnego ctor lub ogólnego. – Spooles

+0

@Spooles: Ale to nie jest konieczne, aby zobaczyć konstruktora, tylko musi zobaczyć 'publicznych readonly pole static' skonstruowana. Wszystkie wartości "KnownSetting " mogą być zbudowane całkowicie wewnętrznie na "KnownSetting ", ale klienci mogą nadal uzyskiwać dostęp do tych wartości przez inne pole w innej klasie. –