Я пытаюсь создать новый объект типа 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.
}
...
}
c#
.net
generics
new-operator
ФУНТ.
источник
источник
Ответы:
Чтобы создать экземпляр универсального типа в функции, вы должны ограничить его флагом «new».
Однако это будет работать только тогда, когда вы хотите вызвать конструктор, у которого нет параметров. Здесь не тот случай. Вместо этого вам нужно будет предоставить другой параметр, который позволяет создавать объекты на основе параметров. Самая простая функция.
Вы можете назвать это так
источник
T result = thunk == null ? new T() : thunk();
для меня это преимущество - объединение логикиT
создания в одном месте, а не созданиеT
внутри, а иногда и вне метода.в .Net 3.5 и после вы можете использовать класс активатора:
источник
Activator.CreateInstance
этой цели, похоже, ваш конструктор вообще не используется, и кто-то может попытаться «очистить» и удалить его (чтобы вызвать ошибку времени выполнения в какое-то случайное время в будущем). Возможно, вы захотите добавить фиктивную функцию, где вы используете этот конструктор, просто чтобы вы получили ошибку компиляции, если попытаетесь удалить ее.Так как никто не удосужился опубликовать ответ «Отражение» (который я лично считаю лучшим ответом), вот так:
Изменить: Этот ответ не рекомендуется из-за Activator.CreateInstance .NET 3.5, однако он все еще полезен в более старых версиях .NET.
источник
Инициализатор объекта
Если ваш конструктор с параметром ничего не делает, кроме установки свойства, вы можете сделать это в C # 3 или лучше, используя инициализатор объекта вместо вызова конструктора (что, как уже упоминалось, невозможно):
Используя это, вы также всегда можете поместить любую логику конструктора в конструктор по умолчанию (пустой).
Activator.CreateInstance ()
В качестве альтернативы вы можете вызвать Activator.CreateInstance () следующим образом:
Обратите внимание, что Activator.CreateInstance может иметь некоторые потери производительности , которых вы можете избежать, если скорость выполнения является главным приоритетом, а другой вариант для вас доступен .
источник
T
защиту его инвариантов (учитывая, чтоT
имеет> 0 зависимостей или обязательных значений, теперь вы можете создавать экземпляры,T
которые находятся в недопустимом / непригодном для использования состоянии. Если толькоT
это не что-то очень простое, например, модель представления DTO, я бы сказал, избегайте этого.Очень старый вопрос, но новый ответ ;-)
Версия ExpressionTree : (Я думаю, самое быстрое и чистое решение)
Как сказал Велли Тамбунан , «мы могли бы также использовать дерево выражений для построения объекта»
Это сгенерирует конструктор (функцию) для заданного типа / параметров. Он возвращает делегата и принимает типы параметров в виде массива объектов.
Вот:
Пример MyClass:
Применение:
Другой пример: передача типов в виде массива
DebugView Expression
Это эквивалентно коду, который генерируется:
Небольшой недостаток
Все параметры valuetypes помещаются в квадрат, когда они передаются как массив объектов.
Простой тест производительности:
Результаты:
Использование
Expressions
в +/- 8 раз быстрее, чем вызов,ConstructorInfo
и в +/- 20 раз быстрее, чем использованиеActivator
источник
var myConstructor = CreateConstructor(typeof(MyClass<int>), typeof(int));
это работает нормально. Я не знаю.Это не будет работать в вашей ситуации. Вы можете указать только ограничение на наличие пустого конструктора:
Что вы можете сделать, это использовать внедрение свойств, определив этот интерфейс:
Тогда вы можете изменить свой метод так:
Другой альтернативой является
Func
метод, описанный JaredPar.источник
Вам нужно добавить где T: new (), чтобы компилятор знал, что T гарантированно предоставит конструктор по умолчанию.
источник
Если вы просто хотите инициализировать поле или свойство элемента с помощью параметра конструктора, в C #> = 3 вы можете сделать это очень просто:
Это то же самое, что сказал Гарри Шатлер, но я бы хотел добавить дополнительную записку.
Конечно, вы можете использовать трюк со свойством, чтобы сделать больше, чем просто установить значение поля. Свойство "set ()" может запускать любую обработку, необходимую для настройки связанных с ним полей, и любую другую потребность в самом объекте, включая проверку на предмет необходимости полной инициализации до использования объекта, имитируя полное конструирование ( да, это уродливый обходной путь, но он преодолевает новое ограничение ($) M $.
Я не могу быть уверен, что это запланированная дыра или случайный побочный эффект, но это работает.
Очень забавно, как люди из MS добавляют новые функции в язык и, похоже, не проводят полный анализ побочных эффектов. Все общее является хорошим доказательством этого ...
источник
Я обнаружил, что получаю ошибку «не могу предоставить аргументы при создании экземпляра параметра типа T», поэтому мне нужно было сделать это:
источник
Если у вас есть доступ к классу, который вы собираетесь использовать, вы можете использовать этот подход, который я использовал.
Создайте интерфейс с альтернативным создателем:
Сделайте ваши классы с пустым создателем и реализуйте этот метод:
Теперь используйте ваши общие методы:
Если у вас нет доступа, оберните целевой класс:
источник
Это немного грязно, и когда я говорю «грязно», я имею в виду отвратительное поведение, но предположим, что вы можете снабдить свой параметризованный тип пустым конструктором, тогда:
Эффективно позволит вам построить объект из параметризованного типа с аргументом. В этом случае я предполагаю, что у конструктора, который я хочу, есть единственный аргумент типа
object
. Мы создаем фиктивный экземпляр T, используя разрешенный ограничением пустой конструктор, а затем используем отражение, чтобы получить один из его других конструкторов.источник
Я иногда использую подход, который похож на ответы с использованием внедрения свойств, но сохраняет код чище. Вместо базового класса / интерфейса с набором свойств он содержит только (виртуальный) метод Initialize (), который действует как «конструктор бедняка». Затем вы можете позволить каждому классу обрабатывать свою собственную инициализацию так же, как это делал бы конструктор, что также добавляет удобный способ обработки цепочек наследования.
Если я часто оказываюсь в ситуациях, когда я хочу, чтобы каждый класс в цепочке инициализировал свои уникальные свойства, а затем вызывал метод Initialize () его родителя, который, в свою очередь, инициализировал уникальные свойства родителя и так далее. Это особенно полезно при наличии разных классов, но с похожей иерархией, например, бизнес-объектов, которые отображаются в / из DTO: s.
Пример, который использует общий словарь для инициализации:
источник
Если все, что вам нужно, это преобразование из ListItem в ваш тип T, вы можете реализовать это преобразование в классе T в качестве оператора преобразования.
источник
Я считаю, что вы должны ограничить T оператором where, чтобы разрешить только объекты с новым конструктором.
Теперь он принимает все, включая объекты без него.
источник