How can I dynamically register generic classes named with Unity?

I have an assembly with many classes (300+) with BaseClass, and I want to register a common class with an interface.

With a unit, you need to register { Name } if you want to allow an array of interface objects. I want an array of objects in MainViewModel automatically.

Is there a way to automate this with reflection? Any suggestions?

Example (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) { } 

Manual working example:

 container.RegisterType<ISuperman, Superman <ClassNumber001>>("ClassNumber001"); container.RegisterType<ISuperman, Superman <ClassNumber002>>("ClassNumber002"); container.RegisterType<IEnumerable<ISuperman>, ISuperman[]>(); 
+5
source share
3 answers

This is what comes to my mind that might work for you ...

You can register a type as follows and should work for an open general .

 container.RegisterType(typeof(ISuperman<>), typeof(Superman<>), ... ); 

Registration of general parameters and types

Hope this helps!

+1
source

Yes, you need to use reflection easily to create all the mappings you need. Since you are using Unity 3, you can use Convention Registration to provide assistance (with a more difficult upgrade) in registering classes.

I took your pseudo code and translated it into real code:

 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(); } } } 

Then use registration by convention to register all generics:

 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>(); 

In the above code, we get all the classes that inherit from BaseClass , and then create the Superman<> type and map it to ISuperman using the name BaseClass . Calling RegisterTypes will be equivalent to calling RegisterType for each BaseClass:

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

Then, when the MainViewModel resolves, MainViewModel through all the ISuperman instances and calls the method that prints:

001 foo
002 Foo

showing that we introduced 2 ISuperman instances: Superman<ClassNumber001> and Superman<ClassNumber002> .

If you need specific registrations for BaseClasses (for example, a non-default time manager), you can use registration by agreement to register them).

+1
source

There are several ways to do this. One of them is the use of XML, which defines a type that MyClass and IMyClass allow to speak, and at runtime it is resolved based on the available assemblies. But the best approach, in my opinion, would be to create a project to which you can delegate responsibility for loading dependencies.

Suppose you create a class like this:

  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 ) } } 

Now, no matter who needs registration, you can call this IMyClass interface so that it registers itself in the container, and a dependency can be introduced depending on which class should perform this task.

0
source

All Articles