Расширяется ли использование дженериков C #? - PullRequest
4 голосов
/ 09 ноября 2010

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

Я хочу иметь возможность создавать дочерние классы из GroupType и / или OptionType. Проблема заключается в том, что я не могу выполнить операцию new для универсальных типов, даже если я указал, что они могут быть только определенного базового типа.

Есть ли способ сделать то, что я пытаюсь сделать?

public class AllInfo<GroupType, OptionType> 
    where GroupType: GroupBase<OptionType>
    where OptionType: OptionBase
{
    public List<string> Names { set; get; }
    public List<GroupType> Groups { set; get; }

    public AllInfo()
    {
        DataSet ds = DatabaseRetreival();
        this.Groups.add(new GroupType(ds["Name"], ds["Type"]));
    }

}

public class GroupBase<OptionType> 
    where OptionType: OptionBase
{
    public string Name { set; get; }
    public string Type { set; get; }
    public List<OptionType> Options { set; get; }

    public GroupBase(string name, string type)
    {
         this.Name = name;
         this.Type = type;

         DataSet ds = DatabaseRetreival(this.Type);
         this.Options.Add(new OptionType(ds["Name"]));
    }
}

public class OptionBase
{
    public string Name { set; get; }

    public OptionBase(string name)
    {
        this.Name = name;
    }
}

Ответы [ 4 ]

4 голосов
/ 09 ноября 2010

Вы должны указать, что классы должны иметь конструктор по умолчанию.

where GroupType: GroupBase<OptionType>, new()

Просмотреть эту статью и перейти к разделу под названием Общие ограничения .

2 голосов
/ 09 ноября 2010

Вы не можете указать, какие конструкторы должен иметь универсальный класс.Конструкторы не наследуются, поэтому даже если указанный вами базовый класс имеет этот конструктор, класс, производный от него, не обязательно должен иметь этот конструктор.

Единственный конструктор, который вам может потребоваться, - это параметр без параметровКонструктор:

where GroupType: GroupBase<OptionType>, new()

Поскольку это позволяет использовать конструктор без параметров, вы также можете использовать виртуальный метод для помещения данных в объект, например:

GroupType group = new GroupType();
group.Init(ds["Name"], ds["Type"]);
this.Groups.add(group);
1 голос
/ 09 ноября 2010

Компилятор не может этого допустить, потому что он не может гарантировать, что OptionType имеет конструктор с правильной подписью.Но вы можете передать фабричную функцию вместо непосредственного вызова конструктора:

public class Foo<T> 
{
    private List<T> myObjects;

    public Foo(Func<string, T> factory))
    {
        myObjects = new List<T>();
        foreach (string s in GetDataStrings())
            myObjects.Add(factory(s));
    }
}

Так что если у вас есть класс Bar с конструктором, принимающим строку, вы делаете это:

Func<string,Bar> barFactory = x => new Bar(x);
var foo = new Foo<Bar>(barFactory);
0 голосов
/ 08 мая 2012

В основе вашей проблемы лежат очень большие объемы связывания классов, которые вы пытаетесь смягчить с помощью наследования / обобщения. Я предлагаю вам пересмотреть, почему вы считаете это необходимым. Этот квест в конечном итоге приведет вас к интерфейсам, программированию на основе сервисов и IoC, таким как Ninject или Castle Windsor.

Однако, если вам нужно быстрое исправление, которое еще больше увеличивает сложность кода (поскольку у вас нет несложных опций, кроме изменения философии кодирования), используйте абстрактный / виртуальный метод , возможно Назовите его Bind (), вместо конструкторов.

[выделено жирным шрифтом для tl; dr]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...