Erstellen Sie Delegierter aus einem Konstruktor eines unbekannten Typs, der eine bekannte Schnittstelle implementiert

StackOverflow https://stackoverflow.com/questions/20353277

Frage

Ich habe einen Typ, der zur Laufzeit erstellt wird (durch Zusammenstellung von CodedOM) und eine bekannte (zur Kompilierzeit) Schnittstelle implementiert.

Angenommen, die Schnittstelle ist IMyInterface, und ich habe die Typinstanz Type myType Dass ich von der Baugruppe erworben habe, habe ich gerade aus dem Codedom zusammengestellt. Die Klasse das myType repräsentiert Geräte IMyInterface.

Ich möchte einen Delegierten bekommen Func<IMyInterface> Das wird beim Aufrufen eine Instanz von zurückgegeben myType.

Etwas, das ich auf diese Weise anrufen möchte:

Func<IMyInterface> createObject = GetObjectCreator<IMyInterface>(myType);
IMyInterface myObject = createObject();

Ich weiß das, wenn ich eine habe MethodInfo m Für eine parameterlose Methode, die eine Instanz des MyType -Objekts zurückgibt, könnte ich so etwas tun:

Func<IMyInterface> createObject =
  ( Func<IMyInterface> )Delegate.CreateDelegate(typeof(Func<IMyInterface>), m);

Aber wenn ich keine solche Methode habe und das einzige, was ich habe, ist der parameterlose Konstruktor des Typs, wie bekomme ich dann diesen Delegierten?

Aktualisieren

Obwohl Fsimonazzis Antwort genau das tat, was ich verlangte, war mein Ansatz etwas anders.

Da ich die Schöpfung und Zusammenstellung der kontrolliere myType Typ, ich habe eine öffentliche statische Methode hinzugefügt, die eine Instanz dieser Art zurückgibt. Nachdem ich diesen Typ zusammengestellt hatte, erhielt ich eine MethodeInfo -Instanz für diese Methode und erstellte den gewünschten Delegierten -Aufruf -Delegaten. Createdelegate.

CodeTypeDeclaration type = new CodeTypeDeclaration
{
    Name = "MyClass",
    IsClass = true,
    TypeAttributes = TypeAttributes.Public
};

type.BaseTypes.Add(new CodeTypeReference(typeof(IMyInterface)));

// fullName is the full name of the myType (including namespace)
var staticInstantiator = new CodeMemberMethod
{
    Name = "__Instantiator",
    ReturnType = new CodeTypeReference("MyNamespace.MyClass"),
    Attributes = MemberAttributes.Public | MemberAttributes.Static
};

staticInstantiator.Statements.Add(
   new CodeMethodReturnStatement(
       new CodeObjectCreateExpression("MyNamespace.MyClass")));

    type.Members.Add(staticInstantiator);

Der obige Code generiert diesen Code und stellt die Klassenerklärung ein

public static MyNamespace.MyClass __Instantiator()
{
    return new MyNamespace.MyClass();
}

Jetzt kompilieren Sie diesen Code und haben Sie eine myType Geben Sie eine Instanz für diese Klasse ein, ich kann es tun

Func<IMyInterface> createObject = ( Func<IMyInterface> )(
    Delegate.CreateDelegate(typeof(Func<IMyInterface>),
                            myType.GetMethod("__Instantiator")) );

IMyInterface obj = createObject(); // This will call MyClass.__Instantiator()
War es hilfreich?

Lösung

Sie können einen einfachen Lambda -Ausdruck zusammenstellen, um Ihren Delegierten zu erhalten.

var del = Expression.Lambda<Func<IMyInterface>>(Expression.New(type)).Compile();

Andere Tipps

Sie können verwenden Activator.CreateInstance( type ) Um tatsächlich eine Instanz Ihres Typs zu erstellen. Wenn Sie dies in einem ausgestopft haben möchten Func<IMyInterface> Dann können Sie es einfach in eine Lambda einwickeln:

Func<IMyInterface> createObject = () => (IMyInterface) Activator.CreateInstance( myType );
IMyInterface myObject = createObject();

AKTUALISIEREN:

Seit Activator.CreateInstance ist offensichtlich nicht das, wonach Sie suchen (obwohl ich mir nicht ganz sicher bin, warum), können Sie nach Überlegungen verwenden, um den parameterlosen Konstruktor des Typs zu finden:

public Func<T> GetObjectCreator<T>( Type type )
{
    // I'd probably add additional checks here to see that the
    // conversion to T is actually possible.

    var ctor = type.GetConstructor( Type.EmptyTypes );

    if( ctor == null ) throw new ArgumentException( "type", "Public parameterless constructor not found." )

    return () => (T) ctor.Invoke( null );
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top