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

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

138 голосов
/ 30 июня 2011

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

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 ().Я исправил это.

Ответы [ 7 ]

367 голосов
/ 30 июня 2011

Взгляните на new Constraint

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);
}
56 голосов
/ 30 июня 2011

Почему никто не предложил Activator.CreateInstance?

http://msdn.microsoft.com/en-us/library/wccyzw83.aspx

T obj = (T)Activator.CreateInstance(typeof(T));
28 голосов
/ 30 июня 2011

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

protected T GetObject<T>(Type[] signature, object[] args)
{
    return (T)typeof(T).GetConstructor(signature).Invoke(args);
}
18 голосов
/ 30 июня 2011

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

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

и вызова его примерно так:

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

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

14 голосов
/ 30 июня 2011

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

protected T GetObject() {
    if (typeof(T).IsValueType || typeof(T) == typeof(string)) {
        return default(T);
    } else {
       return (T)Activator.CreateInstance(typeof(T));
    }
}
7 голосов
/ 30 июня 2011

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

protected T GetObject(params object[] args)
{
    return (T)Impromptu.InvokeConstructor(typeof(T), args);
}
4 голосов
/ 06 декабря 2016

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

  protected T GetObject<T>()
    {
        T obj = default(T);
        obj =Activator.CreateInstance<T>();
        return obj ;
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...