Create a runtime type that inherits an abstract class and implements an interface

Our architecture makes extensive use of the repository template. We have an abstract base class for most repositories that implement some common functions (e.g. get, load, list, etc.). There is an appropriate interface for this base class, IRepository, which defines the public methods of an abstract class. Most objects have an appropriate interface for the repository, for example. the Foo object has an IFooRepository, which in turn implements an IRepository.

What I just described is pretty typical, although I know that this is not without problems. But anyway, this is what we have, and we must live with it.

One of my favorite haters with this type of architecture is to define empty classes that simply inherit the base class of the repository and do nothing else, for example:

public class FooRepository : Repository, IFooRepository { } 

One way around this redundant code is to allow our IOC infrastructure to dynamically create these classes at runtime, so I don't need to write them myself. If I can decide how to create these classes dynamically, then I already know where to connect them to NInject.

Does anyone know some code that could create such a class? Perhaps this can be done using a proxy structure like Castle?

+5
source share
1 answer

I was intrigued by the possibilities raised by your question, so I did some research on how to create repository proxies using either Castles DynamicProxy or the Reflection.Emit classes.

Using the following repository and domain classes (I extended the script to allow repositories to return collections with a strong type):

 public interface IRepository<T> { IEnumerable<T> All { get; } } public abstract class Repository<T> : IRepository<T> { public IEnumerable<T> All { get { return new T[0]; } } } public interface IFooRepository : IRepository<Foo> { } public class Foo { } 

To create a proxy equivalent

 public class FooRepository : Repository<Foo>, IFooRepository { } 

when using DynamicProxy:

 DefaultProxyBuilder proxyBuilder = new DefaultProxyBuilder(); Type baseType = typeof(Repository<>).MakeGenericType(typeof(Foo)); Type[] intefacesImplemented = new Type[] { typeof(IFooRepository) }; Type proxy = proxyBuilder.CreateClassProxyType(baseType, intefacesImplemented, ProxyGenerationOptions.Default); 

When using Reflection.Emit:

 Type baseType = typeof(Repository<>).MakeGenericType(typeof(Foo)); Type repositoryInteface = typeof(IFooRepository); AssemblyName asmName = new AssemblyName( string.Format("{0}_{1}", "tmpAsm", Guid.NewGuid().ToString("N")) ); // create in memory assembly only AssemblyBuilder asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run); ModuleBuilder moduleBuilder = asmBuilder.DefineDynamicModule("core"); string proxyTypeName = string.Format("{0}_{1}", repositoryInteface.Name, Guid.NewGuid().ToString("N")); TypeBuilder typeBuilder = moduleBuilder.DefineType(proxyTypeName); typeBuilder.AddInterfaceImplementation(repositoryInteface); typeBuilder.SetParent(baseType); Type proxy = typeBuilder.CreateType(); 

Then you can register them in the IOC container and use them as usual: (in this case, Windsor):

 WindsorContainer container = new WindsorContainer(); container.Register(Component.For<IFooRepository>().Forward(proxy)); IFooRepository repository = container.Resolve<IFooRepository>(); IEnumerable<Foo> allFoos = repository.All; 

Both Reflection.Emit and DynamicProxy can be configured to use constructors other than the default.

If you are interested theres an excellent tutorial in DynamicProxy, and the documentation for the Reflection.Emit classes can be found.

+18
source

Source: https://habr.com/ru/post/1393610/


All Articles