Создание экземпляра типа без конструктора по умолчанию в C # с использованием отражения
Автор вопроса: AistinaОтветов: 4
В качестве примера возьмем следующий класс:
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 не разрешать создание неинициализированной строки. Вы можете получить исключение: System.ArgumentException: Uninitialized Strings cannot be created. Имейте это в виду. Bartosz Pierzchlewicz 15.01.2010
Спасибо за внимание, но я уже обрабатываю строки и базовые типы отдельно. Aistina 15.01.2010
Первоначально я разместил этот ответ здесь , но вот перепечатка, поскольку это не тот же вопрос, но имеет тот же ответ:
FormatterServices.GetUninitializedObject() создаст экземпляр без вызова конструктора. Я нашел этот класс, используя Reflector и покопавшись в некоторой части ядра. Сетевые классы сериализации.
Я протестировал его, используя приведенный ниже пример кода, и похоже, что он отлично работает:
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;
}
}
}
Ответ 2 · рейтинг 72 · Nick
Используйте эту перегрузку метода CreateInstance:
public static Object CreateInstance(
Type type,
params Object[] args
)
Создает экземпляр указанного типа, используя конструктор, который лучше всего соответствует указанным параметрам.
Когда я тестировал производительность (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) не удастся для строки. Следовательно, для возврата пустой строки применяется специальная обработка строки.
Ответ 4 · рейтинг 4 · Autodidact
Хорошие ответы, но непригодные для использования на компактной платформе 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);
}
}