Создание экземпляра типа без конструктора по умолчанию в C# с помощью отражения


возьмем в качестве примера следующий класс:

class Sometype
{
    int someValue;

    public Sometype(int someValue)
    {
        this.someValue = someValue;
    }
}

затем я хочу создать экземпляр этого типа с использованием отражения:

Type t = typeof(Sometype);
object o = Activator.CreateInstance(t);

обычно это будет работать, однако, потому что SomeType не определен конструктор без параметров, вызов Activator.CreateInstance выдаст исключение типа MissingMethodException сообщением "для этого объекта не определен конструктор без параметров." есть ли альтернативный способ, чтобы создать экземпляр этого типа? Было бы как-то глупо добавлять конструкторы без параметров во все мои классы.

4 81

4 ответа:

Я изначально разместил этот ответ здесь, но вот перепечатка, так как это не тот же самый вопрос, но имеет тот же ответ:

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

используйте эту перегрузку метода CreateInstance:

public static Object CreateInstance(
    Type type,
    params Object[] args
)

создает экземпляр указанного введите с помощью конструктора, что лучше всего соответствует указанным параметрам.

см.:http://msdn.microsoft.com/en-us/library/wcxyzt4d.aspx

Когда Я протестированные производительность (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) будет не в строку. Следовательно, специальная обработка для строки имеет место, чтобы вернуть пустую строку.

хорошие ответы, но непригодны для использования в dot net compact framework. Вот решение, которое будет работать дальше 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);
    }
}