webentwicklung-frage-antwort-db.com.de

Erstellen einer Instanz des Typs ohne Standardkonstruktor in C # mithilfe von Reflection

Nehmen Sie die folgende Klasse als Beispiel:

class Sometype
{
    int someValue;

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

Ich möchte dann eine Instanz dieses Typs mit Reflection erstellen:

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

Normalerweise funktioniert dies jedoch, da SomeType keinen parameterlosen Konstruktor definiert hat, der Aufruf von Activator.CreateInstance löst eine Ausnahme vom Typ MissingMethodException mit der Meldung "Für dieses Objekt ist kein parameterloser Konstruktor definiert." Gibt es eine alternative Möglichkeit, eine Instanz dieses Typs dennoch zu erstellen? Es wäre ziemlich bescheuert, allen meinen Klassen parameterlose Konstruktoren hinzuzufügen.

90
Aistina

Ich habe diese Antwort ursprünglich gepostet hier , aber hier ist ein Nachdruck, da dies nicht die exakt gleiche Frage ist, sondern die gleiche Antwort hat:

FormatterServices.GetUninitializedObject() erstellt eine Instanz, ohne einen Konstruktor aufzurufen. Ich habe diese Klasse gefunden, indem ich Reflector verwendet und einige der wichtigsten .Net-Serialisierungsklassen durchgesehen habe.

Ich habe es mit dem folgenden Beispielcode getestet und es sieht so aus, als ob es großartig funktioniert:

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;
        }
    }
}
130
Jason Jackson

Verwenden Sie diese Überladung der CreateInstance-Methode:

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

Erstellt eine Instanz des angegebenen Typs mit dem Konstruktor, der den angegebenen Parametern am besten entspricht.

Siehe: http://msdn.Microsoft.com/en-us/library/wcxyzt4d.aspx

71
Nick

Wenn ich benchmarked Leistung von (T)FormatterServices.GetUninitializedObject(typeof(T)) es war langsamer. Gleichzeitig führen kompilierte Ausdrücke zu erheblichen Geschwindigkeitsverbesserungen, obwohl sie nur für Typen mit Standardkonstruktor funktionieren. Ich habe einen hybriden Ansatz gewählt:

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

Dies bedeutet, dass der Erstellungsausdruck effektiv zwischengespeichert wird und nur beim ersten Laden des Typs eine Strafe auftritt. Behandelt auch Werttypen auf effiziente Weise.

Nennen:

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

Beachten Sie, dass (T)FormatterServices.GetUninitializedObject(t) schlägt für Zeichenfolge fehl. Daher ist eine spezielle Behandlung für Zeichenfolgen vorhanden, um leere Zeichenfolgen zurückzugeben.

19
nawfal

Gute Antworten, aber auf dem dot net compact Framework unbrauchbar. Hier ist eine Lösung, die auf CF.Net funktioniert ...

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);
    }
}
4
Autodidact