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

І тому я вирішив, що рефлексія тут була найлегшою. Я погоджуюсь, що, безумовно, з огляду на первісну постановку питання, найбільш прийнятною відповіддю для позначення як правильної була відповідна з використанням нового () обмеження. Я це виправив.


27
Ні, я не бачу, що ти намагаєшся і не вмієш робити. Я бачу фрагмент коду, який може бути частиною робочої програми, без контексту, повідомлення про помилки та пояснення.
Ben Voigt

17
Так, я ненавиджу, коли обрана неправильна відповідь!
Девід Геффернан

Відповіді:


409

Погляньте на нове обмеження

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

Tможе бути клас, який не має конструктора за замовчуванням: у цьому випадку new T()буде невірним твердженням. Thenew()Обмеження каже , що 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
@Alex - Коли я прочитав його запитання, я припустив, що він не хоче параметрів: S Проте голосуйте за вас :)
Phill

Чи можливо використовувати щось на кшталт нового обмеження (параметрів)?
Луї Ріс


29

Інший спосіб - використовувати рефлексію:

protected T GetObject<T>(Type[] signature, object[] args)
{
    return (T)typeof(T).GetConstructor(signature).Invoke(args);
}

Спасибі, приятелю - я пішов із цим рішенням, враховуючи контекст методу.
Ханшань

22
Як FYI, це також може бути записано як Activator.CreateInstance (typeof (T), підпис, аргументи); див. 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);
}

4

Щоб отримати це, я спробував наступний код:

  protected T GetObject<T>()
    {
        T obj = default(T);
        obj =Activator.CreateInstance<T>();
        return obj ;
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.