5

Ho un assembly con un sacco di classi (300+) con BaseClass e voglio registrare una classe generica con un'interfaccia.Come posso registrare dinamicamente le classi generiche con un nome con Unity?

Con unità è necessario registrarsi per {Nome} se si desidera risolvere una matrice di oggetti dell'interfaccia. Voglio un array di oggetti nel MainViewModel automaticamente.

C'è un modo per automatizzare questo con la riflessione? Qualche suggerimento?

Esempio (pseudo):

public class BaseClass 
{ 
    public void doFoo(); 
} 

public ClassNumber001 : BaseClass 
{ 
} 
public ClassNumber002 : BaseClass 
{ 
} 

public interface ISuperman 
{ 
} 

public class Superman : ISuperman where T : BaseClass 
{ 
} 

public MainViewModel(IEnumerable<ISuperman> lotsofSuperman) 
{ 
} 

esempio di lavoro a mano:

container.RegisterType<ISuperman, Superman <ClassNumber001>>("ClassNumber001"); 
container.RegisterType<ISuperman, Superman <ClassNumber002>>("ClassNumber002"); 
container.RegisterType<IEnumerable<ISuperman>, ISuperman[]>(); 
+0

È obbligatorio farlo per riflessione? Quale versione di Unity stai usando, sopra 3.x? – gastonmancini

+0

No, non è obbligatorio, ho menzionato il riflesso perché l'ho usato prima. (per trovare tutte le classi 300) Uso Unity 3.5.1404.0. – Tim

risposta

0

ci sono alcuni dei modi in cui questo può essere fatto. Uno è usando XML dove il tipo è definito, diciamo MyClass e IMyClass e durante il runtime si risolve in base agli assiemi disponibili. Ma un approccio migliore a mio avviso sarebbe quello di creare un progetto al quale delegare la responsabilità di caricare le dipendenze.

Diciamo che crea una classe in questo modo:

 public class MyClass : IMyClass 
    { 
     private readonly IUnityContainer _container; 

     #ctor 
     // initialie the container through the constructor 

     public void DoWork<Interface, Class>() where Class: Interface 
     { 
      _container.RegisterType<Interface, Class>(
      //TODO: You can setup the container lifecycle which can be transient 
      // or singleton or custom based on your project requirement 
      ) 
     } 
    } 

Ora chi ha la necessità di registrarsi può chiamare questo IMyClass interfaccia per ottenere per sé registrati nel contenitore e la dipendenza può essere iniettato a qualsiasi classe ha bisogno di svolgere tale compito.

1

Sì, è necessario utilizzare la riflessione su facilmente creare tutti i mapping che si desidera. Poiché stai utilizzando Unity 3, puoi sfruttare Registration by Convention per fornire assistenza (con il sollevamento più pesante) nella registrazione delle classi.

ho preso il codice pseudo e tradotto in codice vero e proprio:

public abstract class BaseClass 
{ 
    public abstract void DoFoo(); 
} 

public class ClassNumber001 : BaseClass 
{ 
    public override void DoFoo() 
    { 
     Console.WriteLine("001 Foo"); 
    } 
} 

public class ClassNumber002 : BaseClass 
{ 
    public override void DoFoo() 
    { 
     Console.WriteLine("002 Foo"); 
    } 
} 

public interface ISuperman 
{ 
    void Do(); 
} 

public class Superman<T> : ISuperman where T : BaseClass 
{ 
    private T baseClass; 

    public Superman(T baseClass) 
    { 
     this.baseClass = baseClass; 
    } 

    public void Do() 
    { 
     this.baseClass.DoFoo(); 
    } 
} 

public class MainViewModel 
{ 
    public MainViewModel(IEnumerable<ISuperman> lotsofSuperman) 
    { 
     foreach(ISuperman superman in lotsofSuperman) 
     { 
      superman.Do(); 
     } 
    } 
} 

Quindi utilizzare registrazione per convenzione di registrare tutti i farmaci generici:

IUnityContainer container = new UnityContainer(); 

container.RegisterTypes(
    AllClasses.FromAssembliesInBasePath().Where(t => typeof(BaseClass).IsAssignableFrom(t)) 
     .Select(t => typeof(Superman<>).MakeGenericType(t)), 
    t => new Type[] { typeof(ISuperman) }, 
    t => t.GetGenericArguments().First().Name, 
    WithLifetime.Transient); 

container.RegisterType<IEnumerable<ISuperman>, ISuperman[]>(); 

container.Resolve<MainViewModel>(); 

Nel codice di cui sopra si ottengono tutti le classi che ereditano da BaseClass e poi costruire un tipo Superman<> e mappa che a ISuperman utilizzando il nome del BaseClass.La chiamata registerTypes sarà equivalente a RegisterType chiedendo ogni BaseClass:

container.RegisterType<ISuperman, Superman<ClassNumber001>("ClassNumber001"); 
container.RegisterType<ISuperman, Superman<ClassNumber002>("ClassNumber002"); 

Poi, quando MainViewModel si risolve si itera su tutte le ISuperman le istanze e chiama un metodo che stampa:

001 Foo
002 foo

mostrando che abbiamo iniettato 2 ISuperman casi: Superman<ClassNumber001> e Superman<ClassNumber002>.

Se sono necessarie registrazioni specifiche per le BaseClasses (ad esempio un gestore di durata non predefinita), è possibile utilizzare la registrazione per convenzione per registrare anche quelle).