从其实现的接口创建类的实例

问题描述 投票:0回答:2

嗨,我正在尝试建立一个通用的UoWFactory来创建一个UnitOfWork(将有一个默认的unitofwork和多个自定义实现)。到目前为止,我已经能够创建工厂方法,该方法创建默认的UoW并将其返回。我已修改以下方法,以根据传递的参数返回指定的UoW。

当前实施

private BaseResult<IUnitOfWork> GetUnitOfWorkByCompiledModel<IUnitOfWork>(DbCompiledModel compiledModel)
{
    return new BaseResult<IUnitOfWork>
    {
        Payload = new DbUnitOfWork(_context, _dbRepository, _mapper, _entityMapper)
    };
}

我希望有这样的东西

private BaseResult<TUoW> GetUnitOfWorkByCompiledModel<IUnitOfWork>(DbCompiledModel compiledModel) where TUoW :Class
{
    return new BaseResult<TUoW>
    {
        //Create instance of type TUoW where TUoW can be IUnitOfWork, ICustomUnitOfWork etc
        //DbUnitOfWork implements IUnitOfWork and CustomUnitOfWork implements ICustomUnitOfWork
        //All the TUoW will have constructors with identical parmeters
    };
}

直接创建类的实例

Activator.CreateInstance (Type type, object[] args);

但是如果我将接口类型作为参数传递,如何创建DbUnitOfWork或CustomUnitOfWork的实例。例如:-

GetUnitOfWorkByCompiledModel<IUnitOfWork>(compiledModel);
GetUnitOfWorkByCompiledModel<ICustomUnitOfWork>(compiledModel);
c# .net factory unit-of-work
2个回答
1
投票

无参数构造函数

您想要的是可能的,除了一件事:您不能将非默认构造函数与泛型类型参数一起使用。您无法避免。

这里的部分问题是,您不能从接口强制执行特定的构造函数方法签名,因此无法保证IUnitOfWork的所有实现都具有相同的构造函数。

这里最简单的解决方案是不使用构造函数,而使用对象初始化:

public interface IUnitOfWork
{
    Foo Foo { get; set; }
}

private BaseResult<TUnitOfWork> GetUnitOfWorkByCompiledModel<TUnitOfWork>(DbCompiledModel compiledModel) where TUnitOfWork : IUnitOfWork, new()
{
    return new BaseResult<TUnitOfWork>
    {
        Payload = new TUnitOfWork()
                  {
                      Foo = myFoo
                  };
    };
}

我认为这很适合您的期望,但变化不大。


解析接口

但是如果我将接口类型作为参数传递,如何创建DbUnitOfWork或CustomUnitOfWork的实例。例如

GetUnitOfWorkByCompiledModel<IUnitOfWork>(compiledModel);GetUnitOfWorkByCompiledModel<ICustomUnitOfWork>(compiledModel);

如果您打算使用没有具体类型的接口类型,那么以上答案是不完整的。

不管泛型类型问题,如果要将接口解析为具体类型,都需要注册要使用的具体类型。

这通常是通过依赖注入框架来完成的。这些框架要求您注册所有必需的类型,例如.NET Core示例:

services.AddTransient<IUnitOfWork, MyUnitOfWork>();
services.AddTransient<ICustomUnitOfWork, MyCustomUnitOfWork>();

然后框架将使用此注册为您自动填写构造函数参数:

public class Example
{
    public Example(ICustomUnitOfWork uow)
    {

    }
}

这里的良好实践方法要求您在整个框架中进行此依赖项注入,因此您无需显式调用任何构造函数(而是让DI框架为您完成)。

可以使用service locator,它实际上是您随意调用的DI框架。用法的一个小例子是:

private BaseResult<TUnitOfWork> GetUnitOfWorkByCompiledModel<TUnitOfWork>(DbCompiledModel compiledModel) where TUnitOfWork : IUnitOfWork, new()
{
    var uow = myServiceLocator.Get<TUnitOfWork>();
    uow.Foo = myFoo;

    return new BaseResult<TUnitOfWork>
    {
        Payload = uow;
    };
}

这将创建一个具体类型的实例,该具体类型已注册为您要用作通用参数的接口。

但是,服务定位器通常被认为是一种反模式],我强烈建议您避免使用比此更清洁的IoC方法。

我无法在单个StackOverflow答案的范围内详细阐述依赖项注入。我建议您查找依赖项注入,因为它确实符合您的期望(通过引用接口获取具体类型)


0
投票

如果DbUnitOfWork类具有正确的值名称,这将是有效的


推荐问答