Création d'instance de type sans constructeur par défaut en C # en utilisant la réflexion
-
23-08-2019 - |
Question
Prenez la classe suivante comme exemple:
class Sometype
{
int someValue;
public Sometype(int someValue)
{
this.someValue = someValue;
}
}
Je veux ensuite créer une instance de réflexion à l'aide de ce type:
Type t = typeof(Sometype);
object o = Activator.CreateInstance(t);
Normalement, cela fonctionne, mais parce que SomeType
n'a pas défini un constructeur sans paramètre, l'appel à Activator.CreateInstance
lancera une exception de type MissingMethodException
avec le message « Aucun constructeur parameterless défini pour cet objet. » Est-ce il une autre façon de créer encore une instance de ce type? Ce serait un peu sucky ajouter constructeurs à tous mes sans paramètre classes.
La solution
Je posté à l'origine cette réponse ici , mais voici une réimpression puisque ce n'est pas exactement la même question, mais a la même réponse:
FormatterServices.GetUninitializedObject()
va créer une instance sans appeler un constructeur. J'ai trouvé cette classe en utilisant réflecteur et creuser à travers une partie du noyau. cours de sérialisation net.
Je l'ai testé à l'aide du code exemple ci-dessous et il semble que cela fonctionne très bien:
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;
}
}
}
Autres conseils
Cette surcharge de la méthode CreateInstance:
public static Object CreateInstance(
Type type,
params Object[] args
)
crée une instance de la spécifiée taper à l'aide du constructeur qui correspond le mieux correspond aux paramètres spécifiés.
Voir: http://msdn.microsoft.com/en-us/ bibliothèque / wcxyzt4d.aspx
Quand je benchmarkée performance de (T)FormatterServices.GetUninitializedObject(typeof(T))
il a été plus lente. En même temps, les expressions compilées vous donnerait de grandes améliorations de la vitesse mais ils ne fonctionnent que pour les types avec constructeur par défaut. Je pris une approche hybride:
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;
}
Cela signifie que la création expression est effectivement mis en mémoire cache et encourt la peine que la première fois que le type est chargé. Traitera des types de valeur trop d'une manière efficace.
Appelez-:
MyType me = New<MyType>.Instance();
Notez que (T)FormatterServices.GetUninitializedObject(t)
échouera pour la chaîne. Par conséquent un traitement spécial pour la chaîne est en place pour retourner une chaîne vide.
Les bonnes réponses, mais inutilisable sur le point compact framework net. Voici une solution qui fonctionnera sur 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);
}
}