C# 解决多接口实现

C# 解决多接口实现,c#,dependency-injection,interface,unity-container,C#,Dependency Injection,Interface,Unity Container,在这种情况下,我的服务接口由两个服务类实现 比如说, IFooService由FooService和FooWithExtraInfoService实现 以下是界面: public interface IFooService { Foo GetEntity(string fieldName, stringFieldValue); } public abstract class FooServiceBase : BarService, IFooService { public Fo

在这种情况下,我的服务接口由两个服务类实现

比如说,

IFooService
FooService
FooWithExtraInfoService
实现

以下是界面:

public interface IFooService
{
    Foo GetEntity(string fieldName, stringFieldValue);
}
public abstract class FooServiceBase : BarService, IFooService
{
    public Foo GetEntity(string fieldName, string fieldValue)
    {
        //here goes the logic
    }
}
这里是FooService

public class FooService: BarService,  IFooService
{
    public FooService(ILogService logservice): base(logservice)
    {
    }

    public Foo GetEntity(string fieldName, string fieldValue)
    {
        //here goes the logic
    }
}
public class FooWithExtraInfoService: BarService, IFooService
{
    public FooWithExtraInfoService(ILogService logservice): base(logservice)
    {
    }

    public Foo GetEntity(string fieldName, string fieldValue)
    {
        //one possible option could be
        var foo = new FooService(logservice).GetEntity(fieldName, fieldValue)
        //do additional stuff
        foo.SomeField = "abc";
    }
}
这里是带有ExtraInfoService的食物

public class FooService: BarService,  IFooService
{
    public FooService(ILogService logservice): base(logservice)
    {
    }

    public Foo GetEntity(string fieldName, string fieldValue)
    {
        //here goes the logic
    }
}
public class FooWithExtraInfoService: BarService, IFooService
{
    public FooWithExtraInfoService(ILogService logservice): base(logservice)
    {
    }

    public Foo GetEntity(string fieldName, string fieldValue)
    {
        //one possible option could be
        var foo = new FooService(logservice).GetEntity(fieldName, fieldValue)
        //do additional stuff
        foo.SomeField = "abc";
    }
}
如您所见,一个选项可能是创建FooService的新对象,然后告诉unity注册类型,其中
IfoosService
FooWithExtraInfoService
实现

比如:

container.RegisterType<IFooService, FooWithExtraInfoService>();
让团结来处理它

或者我应该为
FooWithExtraInfoService
创建不同的界面吗

//one possible option could be
var fooService = new FooService(logservice).GetEntity(fieldName, fieldValue)
//do additional stuff
我不知道现在解决这个问题的最佳方法是什么


任何建议都会有帮助。

如果两者都继承自
BarService
,请创建一个中间类型
FooServiceBase
,以实现该接口:

public interface IFooService
{
    Foo GetEntity(string fieldName, stringFieldValue);
}
public abstract class FooServiceBase : BarService, IFooService
{
    public Foo GetEntity(string fieldName, string fieldValue)
    {
        //here goes the logic
    }
}

FooWithExtraInfoService
FooService
继承它。

我相信在你的情况下,你应该使用
组合
。。。mean有一个类型为
FooService
的属性,如下所示,因为您只想使用
GetEntity()
方法,不打算扩展它

public class FooWithExtraInfoService: BarService
{
   public FooService FooService { get; set; }

当您不能总是仅依靠接口来定义服务消费者所需的行为时,一种替代方法是为DI注册一个或两个具体实现

然后,任何可以安全地依赖于更简单的
IFooService
的类都可以声明对该类的依赖,而那些您知道需要使用
FooWithExtraInfoService
附加功能的类则可以依赖于该类。而
FooWithExtraInfoService
甚至可以声明对
IFooService
的依赖关系,以注入更简单的实现


基本上,接口服务是有用的,但不要在任何情况下都试图使用它们。这似乎是一个很好的选择

decorator模式包装了现有的服务,为其添加了额外的功能,而无需对其进行更改。这允许您将
FooService
所做的工作与
FooWithExtraInfoService
的职责完全分开,并且仍然允许DI容器提供“内部”实例

public class FooWithExtraInfoService : IFooService
{
    private readonly IFooService fooService;

    public FooWithExtraInfoService(IFooService fooService)
    {
        if (fooService == null)
            throw new ArgumentNullException(nameof(fooService));
        this.fooService = fooService;
    }

    public Foo GetEntity(string fieldName, string fieldValue)
    {
        // call the decorated instance of IFooService
        var foo = this.fooService.GetEntity(fieldName, fieldValue);
        //do additional stuff
        foo.SomeField = "abc";
    }
}
然后,您只需将其与DI容器连接起来,如:

var instance = new FooWithExtraInfoService(new FooService(new LogService()));
在Unity中,此注册可以按如下方式进行:

container.RegisterType<ILogService, LogService>();

// Register FooService as a named service
container.RegisterType<IFooService, FooService>("foo");

// Register FooWithExtraInfoService and inject FooService into it
container.RegisterType<IFooService, FooWithExtraInfoService>(
    new InjectionConstructor(new ResolvedParameter<IFooService>("foo")));

这看起来像是
FooWithExtraInfoService
应该是
FooService
,但是有额外的信息,对吗

那么,让它成为一个包含额外信息的
FooService
类。为
FooService
中的
GetEntity
函数指定
virtual
关键字,它可以在子类中重写。这就允许您在
FooWithExtraInfoService
中有一个新的覆盖,它可以简单地调用其父实现

调整后的
FooService
类:

public class FooService: BarService,  IFooService
{
    public FooService(ILogService logservice): base(logservice)
    {
    }

    public virtual Foo GetEntity(string fieldName, string fieldValue)
    {
        //here goes the logic
    }
}
实施:

public class FooWithExtraInfoService: FooService
{
    public FooWithExtraInfoService(ILogService logservice): base(logservice)
    {
    }

    public override Foo GetEntity(string fieldName, string fieldValue)
    {
        Foo foo = base.GetEntity(fieldName, fieldValue)
        //do additional stuff
        foo.SomeField = "abc";
    }
}

那会有什么帮助呢?这里的DI有问题吗?@Rahul据我所知,问题在于“特质”,或者让实现相同接口的两个类型实现相同的行为。My FooWithExtraInfoService必须使用FooService的GetEntity方法,在获取完GetEntity后,FooWithExtraInfoService将向该方法添加其他内容entity@Cybercop然后将其虚拟化,覆盖它并调用基本实现。@Cybercop它没有。您的问题是关于同一接口方法的重复实现,还是关于为同一接口注册两个服务?因为这些都是截然不同的问题,你的问题就在第一个问题的边缘。我喜欢这个答案,直到现在,除非有人在一段时间内想出更好的答案。我会接受这个答案。但我的困惑是,我看到了你发布的答案的链接,对我来说,这有点复杂。你可以简单地在这里发布并更新答案吗?我想这可能会帮助其他人。我已经更新了答案,以包含最简单的Unity decorator注册。如果你将修饰类型作为类型参数传递,注册就会变得简单,无需在注册时解析。请看这个答案的例子:这似乎违背了使用装饰器的目的。但是,Unity在这方面真的很差劲——大多数其他DI容器都有一种注入特定参数的方法,而不必定义整个构造函数签名。