Типовая реализация шаблона enum с помощью дженериков

Как может быть типичный шаблон перечисления в родовом классе? Предположим, что он реализован в этих строках

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

Реализация шаблона верна таким образом, поскольку конструктор остается закрытым, но при использовании этой конструкции он выглядит неправильно:

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

Тогда вариант состоит в том, чтобы разделить его на два класса класса KnownSetting и реализацию установки, но тогда область конструктора не может быть закрытой, чтобы быть полученной изнутри контейнера.

Как этот шаблон может быть реализован так, чтобы его общий вид оставался скрытым от конечного пользователя, но остается строго типизированным? Есть ли более подходящий шаблон или есть лучший способ его реализовать?

Обновление Я добавил второй пример, чтобы проиллюстрировать, что я хочу, чтобы тип настройки был общим.

Ответ 1

Создайте вспомогательный метод в базовом типе, который использует другой тип и создайте известный класс настроек. Вам нужен метод Create, потому что базовым конструктором является Setting (string, object, Func). Вот почему я ввожу еще одну общую переменную (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;
    }
}

Ответ 2

Объявить статические данные в новом классе:

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

Он может иметь одно и то же имя в С#, потому что имена классов уникальны для имени плюс общий аргумент аргументов типа.

Ответ 3

Возможно, я что-то упустил, но почему бы просто не использовать ваш класс KnownSetting<T> как есть, и сделать новые ссылки на те же экземпляры enum из нового класса? Что-то вроде:

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

Затем вы можете использовать значения по желанию:

var x = KnownSettings.Name;