在运行时创建类型,该类型继承一个抽象类并实现一个接口 [英] Create type at runtime that inherits an abstract class and implements an interface

查看:78
本文介绍了在运行时创建类型,该类型继承一个抽象类并实现一个接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们的体系结构广泛使用存储库模式.我们为大多数存储库提供了一个抽象基类,该基类实现了一些常用功能(例如,get,load,list等).此基础类有一个对应的接口IRepository,该接口定义了抽象类的公共方法.大多数实体都有对应的存储库接口,例如Foo实体有一个IFooRepository,它又实现了IRepository.

Our architecture uses the Repository pattern extensively. We have an abstract base class for most of the repositories that implements some common functionality (e.g. get, load, list etc). There is a corresponding interface for this base class, IRepository, which defines the public methods of the abstract class. Most entities have a corresponding interface for the repository, e.g. the Foo entity has an IFooRepository, which in turn implements 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.

我讨厌这种结构的一种方法是必须定义空类,这些空类仅继承基本的Repository类,而无所作为,例如:

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, e.g:

public class FooRepository : Repository, IFooRepository
{
}

解决这些冗余代码的一种方法是允许我们的IOC框架在运行时动态创建这些类,这样我就不必自己编写它们.如果我能弄清楚如何动态创建这些类,那么我已经知道将它们插入NInject的位置.

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. If I can work out how to create these classes dynamically, then I already know where to plug them into NInject.

有人知道一些可以创建此类的代码吗?也许可以使用诸如Castle之类的代理框架来做到这一点?

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的DynamicProxy或Reflection.Emit类生成存储库代理进行了调查.

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.

使用以下存储库和域类(我扩展了方案,以允许存储库返回强类型集合):

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

生成等效于

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

使用DynamicProxy时:

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

使用Reflection.Emit时:

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

然后,您可以在IOC容器中注册它们,并照常使用它们:(在本例中为Windsor):

You can then register them with your 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;

Reflection.Emit和DynamicProxy都可以设置为允许使用非默认构造函数.

Both Reflection.Emit and DynamicProxy can be setup up allow for the use of non-default constructors.

如果您有兴趣,可以在DynamicProxy上找到出色的教程,而Reflection.Emit类的文档可以可以在此处找到.

If you’re interested there’s an excellent tutorial on DynamicProxy, while the documentation for the Reflection.Emit classes can be found here.

这篇关于在运行时创建类型,该类型继承一个抽象类并实现一个接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆