繁体   English   中英

从它实现的接口创建 class 的实例

[英]Create Instance of a class from interface which it implements

嗨,我正在尝试构建一个通用的 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
    };
}

创建 class 的实例很简单

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

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

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

无参数构造函数

您想要的都是可能的,除了一件事:您不能使用具有通用类型 arguments 的非默认构造函数 你无法避免这一点。

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

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

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 核心示例:

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

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

public class Example
{
    public Example(ICustomUnitOfWork uow)
    {
        
    }
}

此处的良好实践方法要求您将这种依赖注入线程化到整个框架中,因此您永远不需要显式调用任何构造函数(而是让 DI 框架为您做这件事)。

可以使用服务定位器,它本质上是一个您随意调用的 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 答案的 scope 中的依赖注入。 我建议您查看依赖注入,因为它完全符合您的期望(通过引用接口获得具体类型)

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

你想改变什么

Payload = new DbUnitOfWork(_context, _dbRepository, _mapper, _entityMapper);

更改为

Payload = new DbUnitOfWork() {
    context = _context, 
    dbRepoitory = _dbRepository,
    mapper = _mapper,
    entityMapper = _entityMapper
};

希望这项工作。

暂无
暂无

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

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