2010-04-12 6 views

Antwort

0

Bearbeiten: Bitte beachten Sie, dass diese Antwort gegeben wurde, bevor die Frage in einer Bearbeitung komplett geändert wurde. Aus diesem Grund bezieht es sich jetzt auf Dinge, die nur in der ursprünglich angegebenen Frage vorhanden waren. Ich bitte um Entschuldigung für all die "dangling pointers". :-)


Kurze Antwort:

Mit dem Code, den Sie geschrieben haben, sehe ich nicht, eine Alternative zu IFoo<T> zu werfen. Wenn Sie dies nicht tun, gibt der Compiler eine Warnung aus (zumindest auf meinem Rechner).

Kompliziertere Antwort:

Gibt es in Ihrem Code haben, um tatsächlich so sein? Genauer gesagt, brauchst du den fraglichen Gips überhaupt?

Ich nehme an, Sie werden Ihre Factory-Methode mehr oder weniger so nennen:

var stringFoo = FooFactory.CreateFoo<string>(); 

Sie haben die Template-Parameter (string in diesem Fall), um ausdrücklich, weil es nicht von jedem Verfahren Argumente abgeleitet werden kann (in diesem Fall, weil es überhaupt keine gibt). Offensichtlich gibt die Factory-Methode eine IFoo<string> zurück.

Nun, da Sie explizit müssen die Art zur Laufzeit angeben, könnte man genauso gut schreiben:

var stringFoo = StringFoo.Create(); 

und hat daher eine Factory-Methode innerhalb StringFoo, wie dies, dass bedingungslos die offensichtlich tut :

public class StringFoo : IFoo<string> 
{ 
    ... 

    public static StringFoo Create() // or alternatively, return an IFoo<string> 
    { 
     return new StringFoo(); 
    } 
} 

dieses Muster zu anderen IFoo<T> Implementierungen zu Durch die Anwendung dieses Sie die if Kette oder switch Block innerhalb FooFactory.CreateFoo<T> speichern, stellen Sie Ihren Code einfacher, und loswerden der Notwendigkeit zu werfen (worüber Sie besorgt sind).

Verstehen Sie mich nicht falsch, ich bin mir bewusst, dass Factory-Methoden, die mehr als einen Objekttyp unterstützen, in einigen Fällen nützlich sind; aber es scheint in deinem Fall mehr Ärger zu verursachen, als es wert ist.


P. S .: Sie könnten ein Aspekt von einigen IoC Container interessant finden.Sie müssen normalerweise konfiguriert werden, und dies umfasst einen Prozess, bei dem Sie konkrete Typen (d. H. Implementierungsklassen) für abstrakte Schnittstellen registrieren. zum Beispiel (hier mit Autofac):

var builder = new ContainerBuilder(); 
builder.RegisterType<StringFoo>().As<IFoo<string>>(); 

später Dann können Sie eine Objektinstanz einer abstrakten Art anfordern:

using (var container = builder.Build()) 
{ 
    var stringFoo = container.Resolve<IFoo<string>>(); 
    ... 
} 

Die Resolve Methode ist der interessante Teil. Sie geben es mit einem abstrakten Typ an und unter Verwendung der registrierten Typen wird ein konkretes Objekt vom Typ StringFoo zurückgegeben. Schau hinein, wenn es sich für dich nicht nach Overkill anhört! so etwas wie dieses :-)

+0

Zum Downvoter: Warum, wenn ich fragen darf? – stakx

+0

@Merritt, keine Sorgen. Sind wir nicht alle hier, um zu lernen? Es macht mir nichts aus, all das geschrieben zu haben, da ich glaube, dass ich auch viel von dem Schreiben/Erklären profitieren kann. – stakx

0

Können Sie das Problem, das Sie mit diesem Mechanismus wird die Lösung beschreiben? Es gibt höchstwahrscheinlich einen klareren Weg, sich dem zu nähern.

bearbeiten

Und ja, riecht der Code. Sie haben den Raum für einen beliebigen Typ offen gelassen, außer Sie beschränken ihn dann auf einen einzelnen Typ und generieren eine Laufzeitausnahme. Warum haben Sie in diesem Fall einen Typparameter?

+3

Nein, bin ich nicht. Ich verstehe nicht die Nützlichkeit einer abstrakten Fabrik, die eine generische Schnittstelle bereitstellt, aber letztendlich nur einen bestimmten konkreten Typ erzeugt. Was Sie beschrieben haben, ist eine Lösung für ein Problem, das Sie noch nicht beschrieben haben. Sagen Sie uns, was dieses * Problem * ist, anstatt Ihrer vorgefassten Meinung, wie Sie es lösen können, und wir werden Ihnen besser helfen können. –

+0

Technologie im Vakuum führt oft zu Lösungen auf der Suche nach einem Problem. Ohne die Situationen zu definieren, die mit diesem Mechanismus behandelt werden, haben Sie keine Kriterien, anhand derer Sie ein Werturteil abgeben können. Wenn Ihre Frage mehr wäre, um festzustellen, ob dieser Ansatz eine praktikable Lösung für ein * Problem * ist, ist das anders. Ich persönlich sehe keine Verwendung für eine generische Fabrik, die nicht generisch ist und Laufzeitfehler verursacht, wenn sie als solche verwendet wird. Es ist, als würde man ein Auto bauen, das erst startet, wenn man in den Supermarkt geht. –

0

Sie könnten versuchen, ...

public static class FooFactory 
{ 
    private static readonly Dictionary<Type, Type> FooTypesLookup; 

    static FooFactory() 
    { 
     FooTypesLookup = (from type in typeof(FooFactory).Assembly.GetExportedTypes() 
          let fooInterface = 
          type.GetInterfaces().FirstOrDefault(
           x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IFoo<>)) 
          where fooInterface != null 
          let firstTypeArgument = fooInterface.GetGenericArguments().First() 
          select new { Type = type, TypeArgument = firstTypeArgument }) 
      .ToDictionary(x => x.TypeArgument, x => x.Type); 
    } 

    public static IFoo<T> CreateFoo<T>() 
    { 
     var genericArgumentType = typeof(T); 
     Type closedFooType; 
     return FooTypesLookup.TryGetValue(genericArgumentType, out closedFooType) 
       ? (IFoo<T>) Activator.CreateInstance(closedFooType) 
       : null; 
    } 
} 

Oder noch besser vorstellen Ihre Lieblings IoC-Container (Windsor, Strukturkarte, etc.) und alle Arten registrieren, die IFoo dort implementieren und dann lösen Sie sie bei Bedarf anstelle des Activator.CreateInstance-Aufrufs auf.

+0

Das Ziel für mich war, Activator.CreateInstance() nicht zu verwenden. – Merritt

Verwandte Themen