简体   繁体   English

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

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

Hi I am trying to build a generic UoWFactory which creates a UnitOfWork(there will be one default unitofwork and multiple custom implementaitons as well).嗨,我正在尝试构建一个通用的 UoWFactory,它创建一个 UnitOfWork(将有一个默认的 unitofwork 和多个自定义实现)。 So far I was able to create factory method which creates default UoW and returns it.到目前为止,我能够创建创建默认 UoW 并返回它的工厂方法。 I have modify the following method to return specified UoW depending on the parameter passed.我已修改以下方法以根据传递的参数返回指定的 UoW。

Current implementation当前实施

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

I wish to have something like this我希望有这样的东西

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

Create an instance of class is straight forward创建 class 的实例很简单

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

But if I pass Interface type as a parameter how to create instance of DbUnitOfWork or CustomUnitOfWork.但是如果我将接口类型作为参数传递,如何创建 DbUnitOfWork 或 CustomUnitOfWork 的实例。 eg:-例如:-

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

Parameterless constructors无参数构造函数

What you want is possible, except for one thing: you can't use non-default constructors with generic type arguments .您想要的都是可能的,除了一件事:您不能使用具有通用类型 arguments 的非默认构造函数 You can't avoid that.你无法避免这一点。

Part of the issue here is that you can't enforce specific constructor method signatures from an interface, so there is no way to guarantee that all implementation of IUnitOfWork are going to have the same constructor.这里的部分问题是您无法从接口强制执行特定的构造函数方法签名,因此无法保证IUnitOfWork的所有实现都将具有相同的构造函数。

The simplest solution here is to step away from using constructors and instead use object initialization:这里最简单的解决方案是不使用构造函数,而是使用 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
                  };
    };
}

I think this suits your expectations while being a minimal change.我认为这符合您的期望,同时也是最小的变化。


Resolving interfaces解析接口

But if I pass Interface type as a parameter how to create instance of DbUnitOfWork or CustomUnitOfWork.但是如果我将接口类型作为参数传递,如何创建 DbUnitOfWork 或 CustomUnitOfWork 的实例。 eg例如

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

If you intend to use interface types without concrete types, then the above answer is incomplete.如果您打算使用没有具体类型的接口类型,那么上面的答案是不完整的。

Regardless of the generic type issue, if you want to resolve an interface into a concrete type, you need to register which concrete type you want to use.不管泛型类型问题如何,如果要将接口解析为具体类型,则需要注册要使用的具体类型。

This is most commonly done via a Dependency Injection framework.这通常通过依赖注入框架完成。 These framework ask you to register all necessary types, eg a .NET Core example:这些框架要求您注册所有必要的类型,例如 .NET 核心示例:

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

And the framework will then use this registration to automatically fill in constructor parameters for you:然后框架将使用此注册自动为您填写构造函数参数:

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

The good practice approach here requires you to thread this dependency injection through your entire framework so you never need to call any constructor explicitly (and instead have the DI framework do it for you).此处的良好实践方法要求您将这种依赖注入线程化到整个框架中,因此您永远不需要显式调用任何构造函数(而是让 DI 框架为您做这件事)。

It is possible to use a service locator , which is essentially a DI framework that you call at-will.可以使用服务定位器,它本质上是一个您随意调用的 DI 框架。 A small example of usage would be:使用的一个小例子是:

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

This creates an instance of whichever concrete type was registered to the interface you're using as the generic parameter.这将创建一个已注册到您用作通用参数的接口的具体类型的实例。

However, service locators are generally considered to be an anti-pattern , and I would strongly suggest that you avoid favor a cleaner IoC approach than this.但是,服务定位器通常被认为是一种反模式,我强烈建议您避免使用比这更干净的 IoC 方法。

I can't elaborate fully on dependency injection in scope of a single StackOverflow answer.我无法详细说明单个 StackOverflow 答案的 scope 中的依赖注入。 I suggest you look up dependency injection as it does exactly what you're expecting (getting a concrete type by referencing an interface)我建议您查看依赖注入,因为它完全符合您的期望(通过引用接口获得具体类型)

This will be work if DbUnitOfWork Class has right name of values如果 DbUnitOfWork Class 具有正确的值名称,这将有效

What you want to change你想改变什么

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

Change as更改为

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

hope this work.希望这项工作。

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

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