Создание экземпляра типа без конструктора по умолчанию в C # с использованием отражения - PullRequest
88 голосов
/ 24 декабря 2008

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

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 ]

129 голосов
/ 24 декабря 2008

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

FormatterServices.GetUninitializedObject() создаст экземпляр без вызова конструктора. Я нашел этот класс, используя Reflector и просматривая некоторые из основных классов сериализации .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;
        }
    }
}
71 голосов
/ 24 декабря 2008

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

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

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

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

19 голосов
/ 23 апреля 2013

Когда я тестировал производительность (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 голосов
/ 22 января 2009

Хорошие ответы, но непригодные для использования в компактной среде 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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...