La creazione di un'istanza di tipo senza costruttore di default in C # utilizzando la riflessione
-
23-08-2019 - |
Domanda
Prendere la seguente classe come esempio:
class Sometype
{
int someValue;
public Sometype(int someValue)
{
this.someValue = someValue;
}
}
Allora voglio creare un'istanza di questo tipo utilizzando la riflessione:
Type t = typeof(Sometype);
object o = Activator.CreateInstance(t);
Normalmente questo funzionerà, tuttavia, a causa SomeType
non ha definito un costruttore senza parametri, la chiamata a Activator.CreateInstance
un'eccezione di tipo MissingMethodException
con il messaggio " Non senza parametri costruttore definito per questo oggetto. " Is c'è un modo alternativo per creare ancora un'istanza di questo tipo? Sarebbe un po sucky aggiungere costruttori senza parametri a tutti i miei corsi.
Soluzione
I originariamente postato questa risposta qui , ma qui è una ristampa dal momento che questo non è esattamente la stessa domanda, ma ha la stessa risposta:
FormatterServices.GetUninitializedObject()
creerà un'istanza senza chiamare un costruttore. Ho trovato questa classe utilizzando Riflettore e scavando attraverso alcuni del nucleo. classi di serializzazione netti.
Ho provato utilizzando il codice di esempio riportato di seguito e sembra che funziona alla grande:
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;
}
}
}
Altri suggerimenti
Utilizzare questo overload del metodo CreateInstance:
public static Object CreateInstance(
Type type,
params Object[] args
)
Crea un'istanza specificata digitare utilizzando il costruttore che meglio corrisponde ai parametri specificati.
See: http://msdn.microsoft.com/en-us/ biblioteca / wcxyzt4d.aspx
Quando benchmark prestazioni di (T)FormatterServices.GetUninitializedObject(typeof(T))
è stato più lento. Allo stesso tempo, le espressioni compilati darebbe grandi miglioramenti di velocità anche se funzionano solo per i tipi con costruttore di default. Ho preso un approccio ibrido:
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;
}
Questo significa l'espressione creare è effettivamente memorizzato nella cache e incorre pena solo la prima volta il tipo viene caricato. Gestirà i tipi di valore anche in un modo efficiente.
Lo chiamano:
MyType me = New<MyType>.Instance();
Si noti che (T)FormatterServices.GetUninitializedObject(t)
non riuscirà per la stringa. trattamento Quindi speciale per corda è posto per tornare stringa vuota.
Le buone risposte, ma inutilizzabile sul quadro compatto dot net. Ecco una soluzione che funziona su 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);
}
}