Erstellen Sie generische Klasse mit internem Konstruktor
-
01-10-2019 - |
Frage
Ist es möglich, ein Objekt mit seinem internen Konstruktor innerhalb einer generischen Methode zu konstruieren?
public abstract class FooBase { }
public class Foo : FooBase {
internal Foo() { }
}
public static class FooFactory {
public static TFooResult CreateFoo<TFooResult>()
where TFooResult : FooBase, new() {
return new TFooResult();
}
}
FooFactory
liegt in der gleichen Anordnung wie Foo
. Klassen rufen Sie die Factory-Methode wie folgt aus:
var foo = FooFactory.CreateFoo<Foo>();
Sie die Kompilierung-Fehler:
‚Foo‘ muss einen nicht-abstrakten Typ mit einem öffentlichen parameterlosen Konstruktor sein, um es zu benutzen als Parameter ‚TFooType‘ in der generischen Art oder Methode 'FooFactory.CreateFoo ()
Gibt es eine Möglichkeit, dies zu umgehen?
Ich habe auch versucht:
Activator.CreateInstance<TFooResult>();
Dies wirft die gleichen Fehler zur Laufzeit.
Lösung
Sie könnten die new()
Einschränkung und Rückkehr entfernen:
//uses overload with non-public set to true
(TFooResult) Activator.CreateInstance(typeof(TFooResult), true);
obwohl der Kunde das auch tun könnte. Dies ist jedoch anfällig für Laufzeitfehler.
Dies ist ein schwieriges Problem in einer sicheren Weise zu lösen, da die Sprache nicht eine abstrakte Konstruktor declaraton zulässt.
Andere Tipps
Das Argument Typ muss eine haben Öffentlichkeit parameterlosen Konstruktor. Bei der Verwendung zusammen mit anderen Einschränkungen, die neue () constraint must angegeben werden zuletzt.
http://msdn.microsoft.com/en-us/library /d5x73970.aspx
edit: also nein, wenn Sie neu () Einschränkung verwenden, können Sie nicht, dass die Klasse übergeben, wenn Sie neue nicht-Einschränkung () verwenden Sie versuchen, mithilfe von Reflektion können neue Instanz erstellen
public static TFooResult CreateFoo<TFooResult>()
where TFooResult : FooBase//, new()
{
return (TFooResult)typeof(TFooResult).GetConstructor(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, new Type[] {}, null).Invoke(new object[]{});
//return new TFooResult();
}
Es kann einige Workarounds wie unten, aber ich glaube nicht, dass du so gehen wollen!
-
Setzen Sie switch-Anweisung innerhalb der Fabrik dass die Instanz erstellen basierend nach Art der Typ-Parameter.
-
Jede konkrete Umsetzung FooBase wird registrieren FooFactory die Fabrik-Methode übergeben es selbst zu schaffen. So FooFactory das interne Wörterbuch verwenden
-
Die Ausweitung auf der analogen Leitung außer Zuordnung zwischen Typ-Parametern und den konkreten Umsetzung wäre externer Code (xml-Datei, Konfiguration usw.). IOC / DI-Container kann auch hier helfen.
public class GenericFactory
{
public static T Create<T>(object[] args)
{
var types = new Type[args.Length];
for (var i = 0; i < args.Length; i++)
types[i] = args[i].GetType();
return (T)typeof(T).GetConstructor(types).Invoke(args);
}
}