В качестве примера возьмем следующий класс:
class Sometype
{
int someValue;
public Sometype(int someValue)
{
this.someValue = someValue;
}
}
Затем я хочу создать экземпляр этого типа, используя отражение:
Type t = typeof(Sometype);
object o = Activator.CreateInstance(t);
Обычно это работает, однако, поскольку SomeType не определил конструктор без параметров, вызов Activator.CreateInstance вызовет исключение типа MissingMethodException с сообщением «Для этого объекта не определен конструктор без параметров.». Есть ли альтернативный способ создания экземпляра этого типа? Было бы отстойно добавлять конструкторы без параметров ко всем моим классам.
Спасибо за внимание, но я уже обрабатываю строки и базовые типы отдельно.





Первоначально я опубликовал этот ответ здесь, но вот его перепечатка, поскольку это не тот же вопрос, но имеет тот же ответ:
FormatterServices.GetUninitializedObject() создаст экземпляр без вызова конструктора. Я нашел этот класс, используя Отражатель и покопавшись в некоторых основных классах сериализации .Net.
Я протестировал его, используя приведенный ниже пример кода, и похоже, что он отлично работает:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Runtime.Serialization;
namespace NoConstructorThingy
{
class Program
{
static void Main(string[] args)
{
MyClass myClass = (MyClass)FormatterServices.GetUninitializedObject(typeof(MyClass)); //does not call ctor
myClass.One = 1;
Console.WriteLine(myClass.One); //write "1"
Console.ReadKey();
}
}
public class MyClass
{
public MyClass()
{
Console.WriteLine("MyClass ctor called.");
}
public int One
{
get;
set;
}
}
}
Отлично, похоже, это именно то, что мне нужно. Я предполагаю, что неинициализированный означает, что вся его память будет обнулена? (Подобно тому, как создаются экземпляры структур)
Значение по умолчанию для каждого типа будет значением по умолчанию. Таким образом, объекты будут иметь значение null, int 0 и т. д. Я думаю, что любая инициализация на уровне класса происходит, но конструктор не запускается.
@JSBangs, отстой, вы даете вполне законный ответ. Ваш комментарий и другой ответ на самом деле не затрагивают заданный вопрос. Если вы чувствуете, что у вас есть лучший ответ, дайте его. Но предоставленный мной ответ подчеркивает, как использовать документированный класс так же, как другие классы сериализации используют этот код.
@JSBangs FormatterServices (msdn.microsoft.com/en-us/library/…) не недокументирован.
использование GetUninitializedObject, похоже, зависит от вашей конкретной цели: Поскольку новый экземпляр объекта инициализируется нулем и конструкторы не запускаются, объект может не представлять состояние, которое этот объект считает допустимым. Текущий метод следует использовать для десериализации только тогда, когда пользователь намеревается немедленно заполнить все поля. Он не создает неинициализированную строку, поскольку создание пустого экземпляра неизменяемого типа не имеет смысла.
@Cal - Да, это очень мощная функция, и ее следует использовать с осторожностью. Я только Когда-либо использовал эту функцию в одном месте в моем коде за последние 3 года с тех пор, как я опубликовал это.
Как я могу вызвать все конструкторы по умолчанию (и базу для унаследованных) позже?
Используйте эту перегрузку метода CreateInstance:
public static Object CreateInstance(
Type type,
params Object[] args
)
Creates an instance of the specified type using the constructor that best matches the specified parameters.
См .: http://msdn.microsoft.com/en-us/library/wcxyzt4d.aspx
Это решение упрощает проблему. Что делать, если я не знаю свой тип и говорю «просто создайте объект типа в этой переменной типа»?
Хорошие ответы, но непригодные для использования на компактной платформе dot net. Вот решение, которое будет работать на CF.Net ...
class Test
{
int _myInt;
public Test(int myInt)
{
_myInt = myInt;
}
public override string ToString()
{
return "My int = " + _myInt.ToString();
}
}
class Program
{
static void Main(string[] args)
{
var ctor = typeof(Test).GetConstructor(new Type[] { typeof(int) });
var obj = ctor.Invoke(new object[] { 10 });
Console.WriteLine(obj);
}
}
Так я бы назвал конструктор не по умолчанию. Я не уверен, что когда-нибудь захочу создать объект, вообще не вызывая конструктор.
Вы можете создать объект без вызова конструкторов, если вы пишете собственные сериализаторы.
Да, это точный сценарий использования, для которого был задан вопрос :)
@Aistina Возможно, вы могли бы добавить эту информацию к вопросу? Большинство людей были бы против создания объектов без обращения к своим ctors и потратили бы время, чтобы поспорить с вами по этому поводу, но ваш вариант использования действительно оправдывает это, поэтому я думаю, что это очень актуально для самого вопроса.
Когда я проверенный производительность (T)FormatterServices.GetUninitializedObject(typeof(T)) была медленнее. В то же время скомпилированные выражения дадут вам значительное повышение скорости, хотя они работают только для типов с конструктором по умолчанию. Я использовал гибридный подход:
public static class New<T>
{
public static readonly Func<T> Instance = Creator();
static Func<T> Creator()
{
Type t = typeof(T);
if (t == typeof(string))
return Expression.Lambda<Func<T>>(Expression.Constant(string.Empty)).Compile();
if (t.HasDefaultConstructor())
return Expression.Lambda<Func<T>>(Expression.New(t)).Compile();
return () => (T)FormatterServices.GetUninitializedObject(t);
}
}
public static bool HasDefaultConstructor(this Type t)
{
return t.IsValueType || t.GetConstructor(Type.EmptyTypes) != null;
}
Это означает, что выражение create эффективно кэшируется и влечет за собой штраф только при первой загрузке типа. Будет также эффективно обрабатывать типы значений.
Назови это:
MyType me = New<MyType>.Instance();
Обратите внимание, что (T)FormatterServices.GetUninitializedObject(t) не сможет выполнить строку. Следовательно, для возврата пустой строки предусмотрена специальная обработка строки.
Странно, как взгляд на одну строчку чьего-то кода может спасти день. Спасибо, сэр! Причины производительности привели меня к вашему сообщению, и трюк сделан :) Классы FormatterServices и Activator неэффективны по сравнению с скомпилированными выражениями, как жаль, что активаторы повсюду.
@nawfal Что касается вашей специальной обработки строки, я знаю, что она не удалась бы для строки без этой специальной обработки, но я просто хочу знать: будет ли она работать для других типов все?
@ Sнаđошƒаӽ к сожалению нет. Данный пример является базовым, и .NET имеет много разных типов. Например, подумайте, если вы передадите тип делегата, как вы предоставите ему экземпляр? Или иначе, если конструктор выдает, что вы можете с этим поделать? Много разных способов справиться с этим. С тех пор, как я ответил на это, обновлено, чтобы обрабатывать гораздо больше сценариев в моей библиотеке. Он пока нигде не опубликован.
FormatterServices.GetUninitializedObjectне позволяет создавать неинициализированную строку. Вы можете получить исключение:System.ArgumentException: Uninitialized Strings cannot be created.Имейте это в виду.