C # Создать новый T ()

159

Вы можете увидеть, что я пытаюсь (но не могу) сделать с помощью следующего кода:

protected T GetObject()
{
    return new T();
}

Любая помощь будет принята с благодарностью.

РЕДАКТИРОВАТЬ:

Контекст был следующим. Я играл с пользовательским классом контроллеров для всех контроллеров, используя стандартизированные методы. Поэтому в контексте мне нужно было создать новый экземпляр объекта типа контроллера. На момент написания статьи это было что-то вроде:

public class GenericController<T> : Controller
{
    ...

    protected T GetObject()
    {
        return (T)Activator.CreateInstance(ObjectType);
    }        

    public ActionResult Create()
    {
        var obj = GetObject()

        return View(obj);
    }

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

Ханьшань
источник
27
Нет, я не понимаю, что вы пытаетесь и не можете сделать. Я вижу фрагмент кода, который может быть частью работающей программы, без контекста, без сообщения об ошибке и без объяснения.
Бен Фойгт
17
Ой, я ненавижу, когда выбран неправильный ответ!
Дэвид Хеффернан

Ответы:

409

Посмотрите на новые ограничения

public class MyClass<T> where T : new()
{
    protected T GetObject()
    {
        return new T();
    }
}

Tможет быть классом, который не имеет конструктора по умолчанию: в этом случае new T()будет недопустимый оператор. new()Ограничение говорит , что Tдолжен иметь конструктор по умолчанию, что делает new T()легальными.

Вы можете применить то же ограничение к универсальному методу:

public static T GetObject<T>() where T : new()
{
    return new T();
}

Если вам нужно передать параметры:

protected T GetObject(params object[] args)
{
    return (T)Activator.CreateInstance(typeof(T), args);
}
Алекс Аза
источник
2
Спасибо, приятель - я рад, что узнал это сегодня. Учитывая контекст моего метода, я выбрал решение для отражения. Ура!
Ханьшань
8
@nulliusinverba - хм ... было бы хорошо, если бы вы показали контекст вашего метода в вопросе.
Алекс Аза
1
@nulliusinverba - вы не указали в вопросе, что вам нужны параметры.
Алекс Аза
1
@ Алекс - Когда я читал его вопрос, я предполагал, что ему не нужны параметры: S, однако, проголосуйте за вас :)
Фил
Можно ли использовать что-то вроде ограничения new (параметры)?
Луи Рис
29

Другой способ заключается в использовании отражения:

protected T GetObject<T>(Type[] signature, object[] args)
{
    return (T)typeof(T).GetConstructor(signature).Invoke(args);
}
Шон Томан
источник
Спасибо, приятель - я пошел с этим решением, учитывая контекст метода.
Ханьшань
22
Также как FYI, это можно записать как Activator.CreateInstance (typeof (T), signature, args); см. msdn.microsoft.com/en-us/library/4b0ww1we.aspx для получения более подробной информации.
Крис Бакстер
@Calgary Coder: какая польза для подписи типа [], вы можете просто вызвать CreateInstance с параметрами напрямую, без явного указания подписи. В обоих случаях вы получите MissingMethodException, если соответствующий конструктор не существует.
Борис Б.
4
Даже если этот ответ лучше всего работает для вас, он явно не самый лучший для сообщества. Люди, которые ищут этот вопрос, ищут ответ снизу, правда.
Ловушка
И что именно это за контекст? Пожалуйста, добавьте его к первоначальному вопросу.
Джеймс
18

Просто для завершения, лучшее решение здесь часто требует аргумента фабричной функции:

T GetObject<T>(Func<T> factory)
{  return factory(); }

и назовите это как-то так:

string s = GetObject(() => "result");

Вы можете использовать это, чтобы требовать или использовать доступные параметры, если это необходимо.

Джоэл Коухорн
источник
16

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

protected T GetObject() {
    if (typeof(T).IsValueType || typeof(T) == typeof(string)) {
        return default(T);
    } else {
       return (T)Activator.CreateInstance(typeof(T));
    }
}
Лукас Ценовский
источник
7

Поскольку он помечен как C # 4. С открытой структурой sourece ImpromptuIntereface он будет использовать dlr для вызова конструктора, он значительно быстрее, чем Activator, когда у вашего конструктора есть аргументы, и незначительно медленнее, когда его нет. Однако главное преимущество заключается в том, что он будет правильно обрабатывать конструкторы с необязательными параметрами C # 4.0, чего не сделает Activator.

protected T GetObject(params object[] args)
{
    return (T)Impromptu.InvokeConstructor(typeof(T), args);
}
jbtule
источник
4

Чтобы получить это, я попробовал следующий код:

  protected T GetObject<T>()
    {
        T obj = default(T);
        obj =Activator.CreateInstance<T>();
        return obj ;
    }
UJS
источник