Programing

리플렉션을 사용하여 C #에서 기본 생성자없이 유형의 인스턴스 만들기

lottogame 2020. 9. 2. 20:24
반응형

리플렉션을 사용하여 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


나는 원래이 답변을 여기에 게시 했지만 이것은 정확히 동일한 질문이 아니지만 동일한 답변을 가지고 있기 때문에 여기에 재판이 있습니다.

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

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

This means the create expression is effectively cached and incurs penalty only the first time the type is loaded. Will handle value types too in an efficient manner.

Call it:

MyType me = New<MyType>.Instance();

Note that (T)FormatterServices.GetUninitializedObject(t) will fail for string. Hence special handling for string is in place to return empty string.


Good answers but unusable on the dot net compact framework. Here is a solution that will work on 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);
    }
}

참고URL : https://stackoverflow.com/questions/390578/creating-instance-of-type-without-default-constructor-in-c-sharp-using-reflectio

반응형