Activator.CreateInstance(Тип) для типа без конструктора без параметров
Считывая существующий код на работе, я задавался вопросом, почему это может сработать. У меня есть класс, определенный в сборке:
[Serializable]
public class A
{
private readonly string _name;
private A(string name)
{
_name = name;
}
}
И в другой сборке:
public void f(Type t) {
object o = Activator.CreateInstance(t);
}
и этот простой вызов f(typeof(A))
Я ожидал исключения из-за отсутствия конструктора без параметров, потому что AFAIK, если объявлен ctor, компилятор не должен генерировать стандартный публичный конструктор без параметров.
Этот код работает под .NET 2.0.
[РЕДАКТИРОВАТЬ] Извините, но я неправильно понял фактический код... Образец, который я предоставил, не иллюстрирует его. Я принял ответ JonH, потому что он предоставил хорошую информацию.
Ответы
Ответ 1
Смотрите: Создание экземпляра типа без конструктора по умолчанию в С# с использованием отражения
Здесь и в будущем, это касается С# 4.0:
Отправлено Microsoft на 04.01.2010 в 2:08 вечера
Мы рассмотрели вашу ошибку и определили, что поведение, которое вы описали по дизайну. Сейчас мы архивирование этой проблемы. Спасибо за использование Visual Studio и .Net Framework!
Есть много перегрузок Activator.CreateInstance, тот, который принимает только один параметр типа вызывает параметр без параметров конструктор. Конструкторы, которые принимают необязательный параметр, такой как ваш пример не является стандартным Конструкторы. Чтобы вызвать их, вам нужно в:
-
- используйте перегрузку, которая принимает массив аргументов
- Передать в Type.Missing как аргумент
- Укажите необязательный параметрParamBinding в BindingFlags
Вот пример:
Activator.CreateInstance(typeof(MyClassName),
BindingFlags.CreateInstance |
BindingFlags.Public |
BindingFlags.Instance |
BindingFlags.OptionalParamBinding,
null, new Object[] {Type.Missing}, null);
Спасибо,
Weitao Su
Корпорация Microsoft.
Ответ 2
Альтернативой является
object obj = System.Runtime.Serialization.FormatterServices
.GetUninitializedObject(t);
который создает объект в памяти, но не запускает какой-либо конструктор. Страшно.
Ответ 3
Это может быть невыполнимо для вас, но самое простое - передать список аргументов после такого типа:
Activator.CreateInstance(t, "name" );
Вам нужно подумать о том, что действительно пытается сделать f(). Должен ли он вообще создавать объект типа A? Какие еще классы он будет создавать?
Одна из возможностей состоит в том, чтобы иметь оператор switch внутри f(), который передает правильные параметры CreateInstance() для класса A. Это не будет масштабироваться, но это может быть не проблемой для вас.
Ответ 4
Есть два путаных аромата CreateInstance
: один, который принимает объект типа System.Type
как параметр , другой, который принимает параметр типа T
.
Первый:
object Activator.CreateInstance(type As Type) { }
Второй:
T Activator.CreateInstance<T>() { }
Второй - тот, который не работает для класса без открытого конструктора без параметров.
Обратите внимание, что почти никогда не имеет смысла даже использовать второй; в любом случае, когда он будет использоваться, было бы лучше иметь ограничение where T : new()
для вашего класса и просто использовать конструктор T
.
документация MSDN соглашается:
В общем, нет смысла использовать CreateInstance
в коде приложения, потому что тип должен быть известен в время компиляции. Если тип известен в время компиляции, нормальное создание можно использовать синтаксис (оператор new
в С#, new
в Visual Basic, gcnew
в С++).
РЕДАКТИРОВАТЬ. Возможно, я сказал слишком рано; похоже, первая версия тоже не должна работать.