Передача аргументов в C # generic new () шаблонного типа - PullRequest
382 голосов
/ 08 мая 2009

Я пытаюсь создать новый объект типа T через его конструктор при добавлении в список.

Я получаю сообщение об ошибке компиляции:

'T': невозможно предоставить аргументы при создании экземпляра переменной

Но у моих классов есть аргумент конструктора! Как я могу сделать эту работу?

public static string GetAllItems<T>(...) where T : new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
       tabListItems.Add(new T(listItem)); // error here.
   } 
   ...
}

Ответы [ 13 ]

0 голосов
/ 30 января 2017

Я иногда использую подход, который напоминает ответы с помощью внедрения свойств, но сохраняет код чище. Вместо базового класса / интерфейса с набором свойств он содержит только (виртуальный) метод Initialize (), который действует как «конструктор бедняка». Затем вы можете позволить каждому классу обрабатывать свою собственную инициализацию так же, как это делал бы конструктор, что также добавляет удобный способ обработки цепочек наследования.

Если часто оказываются в ситуациях, когда я хочу, чтобы каждый класс в цепочке инициализировал свои уникальные свойства, а затем вызывал метод Initialize () его родителя, который в свою очередь инициализировал уникальные свойства родителя и так далее. Это особенно полезно при наличии разных классов, но с похожей иерархией, например бизнес-объектов, которые отображаются в / из DTO: s.

Пример, использующий общий словарь для инициализации:

void Main()
{
    var values = new Dictionary<string, int> { { "BaseValue", 1 }, { "DerivedValue", 2 } };

    Console.WriteLine(CreateObject<Base>(values).ToString());

    Console.WriteLine(CreateObject<Derived>(values).ToString());
}

public T CreateObject<T>(IDictionary<string, int> values)
    where T : Base, new()
{
    var obj = new T();
    obj.Initialize(values);
    return obj;
}

public class Base
{
    public int BaseValue { get; set; }

    public virtual void Initialize(IDictionary<string, int> values)
    {
        BaseValue = values["BaseValue"];
    }

    public override string ToString()
    {
        return "BaseValue = " + BaseValue;
    }
}

public class Derived : Base
{
    public int DerivedValue { get; set; }

    public override void Initialize(IDictionary<string, int> values)
    {
        base.Initialize(values);
        DerivedValue = values["DerivedValue"];
    }

    public override string ToString()
    {       
        return base.ToString() + ", DerivedValue = " + DerivedValue;
    }
}
0 голосов
/ 12 ноября 2010

Это отчасти гадость, и когда я говорю гадость, я могу иметь в виду отвратительность, но предположим, что вы можете снабдить свой параметризованный тип пустым конструктором, тогда:

public static T GetTInstance<T>() where T: new()
{
    var constructorTypeSignature = new Type[] {typeof (object)};
    var constructorParameters = new object[] {"Create a T"};
    return (T) new T().GetType().GetConstructor(constructorTypeSignature).Invoke(constructorParameters);
}

Эффективно позволит вам построить объект из параметризованного типа с аргументом. В этом случае я предполагаю, что у конструктора, который я хочу, есть единственный аргумент типа object. Мы создаем фиктивный экземпляр T с использованием пустого конструктора, разрешенного ограничением, а затем используем отражение, чтобы получить один из его других конструкторов.

0 голосов
/ 08 мая 2009

Я считаю, что вы должны ограничить T оператором where, чтобы разрешить только объекты с новым конструктором.

Теперь он принимает все, включая объекты без него.

...