【问题标题】:Create type at runtime that inherits an abstract class and implements an interface在运行时创建继承抽象类并实现接口的类型
【发布时间】:2012-02-21 15:09:12
【问题描述】:

我们的架构广泛使用存储库模式。 对于大多数实现一些通用功能(例如获取、加载、列表等)的存储库,我们都有一个抽象基类。这个基类有一个对应的接口IRepository,它定义了抽象类的公共方法。大多数实体都有相应的存储库接口,例如Foo 实体有一个 IFooRepository,它又实现了 IRepository。

我刚才描述的是相当典型的,尽管我知道它并非没有问题。但无论如何,这是我们所拥有的,我们必须忍受它。

我最讨厌这种架构的一个原因是必须定义空类,这些空类只是继承基础 Repository 类而不做任何其他事情,例如:

public class FooRepository : Repository, IFooRepository
{
}

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

有谁知道一些可以创建这样一个类的代码?也许这可以通过诸如 Castle 之类的代理框架来完成?

【问题讨论】:

  • 似乎IFooRepository 没有声明任何成员。为什么在那种情况下你还拥有它?
  • @cbp - 我不确定我是否完全理解您期望的答案类型,但听起来您可以从使用 Reflection.Emit 生成您的类型中受益。跨度>
  • @M.Babcock 是的,我相信。这个答案有类似的东西,但看起来并不容易:stackoverflow.com/questions/847809/…
  • @svick 您需要它,以便可以将存储库作为依赖项注入到需要它的服务中。另一种方法是让服务只需要基本的 IRepository 接口,如果这就是他们所需要的,但这往往很难在 IOC 容器中设置。

标签: c#


【解决方案1】:

我对您的问题提出的可能性很感兴趣,因此我对您将如何使用 Castle 的 DynamicProxy 或 Reflection.Emit 类生成存储库代理进行了一些调查。

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

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

使用动态代理时:

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 时:

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

WindsorContainer container = new WindsorContainer();

container.Register(Component.For<IFooRepository>().Forward(proxy));

IFooRepository repository = container.Resolve<IFooRepository>();

IEnumerable<Foo> allFoos = repository.All;

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

如果您有兴趣,可以在 DynamicProxy 上找到出色的 tutorial,而 Reflection.Emit 类的文档可以在 here 找到。

【讨论】:

    猜你喜欢
    • 2011-11-03
    • 2012-04-11
    • 1970-01-01
    • 2012-07-15
    • 2018-04-05
    • 1970-01-01
    • 2013-10-17
    • 2011-09-16
    • 1970-01-01
    相关资源
    最近更新 更多