简体   繁体   English

在运行时创建类型,继承抽象类并实现接口

[英]Create type at runtime that inherits an abstract class and implements an interface

Our architecture uses the Repository pattern extensively. 我们的架构广泛使用Repository模式。 We have an abstract base class for most of the repositories that implements some common functionality (eg get, load, list etc). 我们有大多数存储库的抽象基类,它们实现了一些常用功能(例如get,load,list等)。 There is a corresponding interface for this base class, IRepository, which defines the public methods of the abstract class. 这个基类IRepository有一个相应的接口,它定义了抽象类的公共方法。 Most entities have a corresponding interface for the repository, eg the Foo entity has an IFooRepository, which in turn implements IRepository. 大多数实体都有一个相应的存储库接口,例如,Foo实体有一个IFooRepository,后者又实现了IRepository。

What I have just described is fairly typical, although I know it is not without problems. 我刚才描述的是相当典型的,虽然我知道它并非没有问题。 But anyway, it is what we have and we have to live with it. 但无论如何,这是我们拥有的,我们必须忍受它。

One of my pet-hates with this type of architecture is having to define empty classes that simply inherit the base Repository class and do nothing else, eg: 我对这种类型的体系结构的宠爱之一就是必须定义简单地继承基本Repository类的空类,而不执行任何其他操作,例如:

public class FooRepository : Repository, IFooRepository
{
}

One way of getting around this redundant code, is to allow our IOC framework to dynamically create these classes at runtime, so that I don't have to write them myself. 解决这个冗余代码的一种方法是允许我们的IOC框架在运行时动态创建这些类,这样我就不必自己编写它们了。 If I can work out how to create these classes dynamically, then I already know where to plug them into NInject. 如果我可以弄清楚如何动态创建这些类,那么我已经知道将它们插入NInject的位置。

Does anyone know of a some code that can create such a class? 有谁知道一些可以创建这样一个类的代码? Perhaps this can be done with a Proxy framework such as Castle? 也许这可以通过像Castle这样的代理框架来完成?

I was intrigued by the possibilities raised by your question so I did some investigation into how you would generate the repository proxies using either Castle's DynamicProxy or the Reflection.Emit classes. 我对您提出的问题提出的可能性很感兴趣,因此我对如何使用Castle的DynamicProxy或Reflection.Emit类生成存储库代理进行了一些调查。

Using the following repository and domain classes (I expanded the scenario to allow repositories to return strongly type collections): 使用以下存储库和域类(我扩展了场景以允许存储库返回强类型集合):

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 generate a proxy equivalent to 生成相当于的代理

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

when using DynamicProxy: 使用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: 使用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();

You can then register them with your IOC container and use them as usual: (in this case Windsor): 然后,您可以将它们与您的IOC容器一起注册并像往常一样使用它们(在本例中为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 setup up allow for the use of non-default constructors. 可以设置Reflection.Emit和DynamicProxy,允许使用非默认构造函数。

If you're interested there's an excellent tutorial on DynamicProxy, while the documentation for the Reflection.Emit classes can be found here . 如果您有兴趣,可以在DynamicProxy上找到一个很好的教程 ,而在这里可以找到Reflection.Emit类的文档。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM