C# 依赖注入和类继承
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/907746/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Dependency Injection and Class Inheritance
提问by nkirkes
I feel like this is something I should already know, but I'm just not firing on all engines today...
我觉得这是我应该已经知道的事情,但我今天没有在所有引擎上开火......
I have a base class with a single ctor that takes an implementation of an interface as it's only parameter. I'm using a DI framework and have my component registrations all set up and working fine.
我有一个带有单个 ctor 的基类,它采用接口的实现,因为它只是参数。我正在使用 DI 框架,并且我的组件注册全部设置好并且工作正常。
When I inherit from this base class, unless I pass in a value to the base constructor, I have to define a parameterless ctor, which bypasses the DI.
当我从这个基类继承时,除非我向基构造函数传递一个值,否则我必须定义一个无参数的ctor,它绕过DI。
So right now I have:
所以现在我有:
public class MyObjectBase
{
IMyRequiredInterface _InterfaceImpl;
public MyObjectBase(IMyRequiredInterface interfaceImpl)
{
_InterfaceImpl = interfaceImpl;
}
...
}
public class AnotherObject : MyObjectBase
{
public AnotherObject()
{
}
...
}
So, out of the gate this fails. I get errors when AnotherObject is instantiated indicating that there is no base class ctor that takes 0 parameters. Ok, I get that. But now I have a choice: either modify the descendant class ctor to take a similar parameter and pass that value on to the base ctor, or wire up a ctor chain in the base class that forces me to bypass DI and create a concrete implementation of the required interface and pass it in as part of the parameterless ctor declaration.
所以,走出大门,这失败了。实例化 AnotherObject 时出现错误,表明没有采用 0 参数的基类构造函数。好的,我明白了。但现在我有一个选择:要么修改后代类 ctor 以采用类似的参数并将该值传递给基类 ctor,要么在基类中连接一个 ctor 链,迫使我绕过 DI 并创建一个具体的实现所需的接口并将其作为无参数 ctor 声明的一部分传入。
The goal is to meet the requirement of the base class without the descendant classes knowing anything about it.
目标是满足基类的要求,而后代类对此一无所知。
Maybe I'm going about this all wrong, but it's bugging me. Any thoughts on a better way to handle this? I feel like I've got to be missing something simple...
也许我对这一切的看法都错了,但这让我很烦恼。关于处理这个问题的更好方法的任何想法?我觉得我必须错过一些简单的东西......
采纳答案by yfeldblum
The correct approach is:
正确的做法是:
public class AnotherObject : MyObjectBase {
public AnotherObject(IMyRequiredInterface interfaceImpl) :
base(interfaceImpl) {
}
}
You specifically asked for an approach other than this approach. Why?
您特别要求采用这种方法以外的方法。为什么?
The goal is to meet the requirement of the base class without the descendant classes knowing anything about it.
目标是满足基类的要求,而后代类对此一无所知。
That's generally the wrong thing to do. Why do you want to do it?
这通常是错误的做法。你为什么要这样做?
Update:
更新:
Based on your later comment, you should probably use (and configure your container to use) property injection instead of constructor injection. That will get you all of your requirements.
根据您后来的评论,您可能应该使用(并配置您的容器以使用)属性注入而不是构造函数注入。这将满足您的所有要求。
回答by cjs
Err....the whole point of inheriting from MyObjectBase
is that, as it were, you get the good and the bad, as far as the behaviour goes. If you can't create a MyObjectBase
without an object implementing IMyRequiredInterface
, you can't create a subclass without such an object either.
呃......继承的全部意义MyObjectBase
在于,就行为而言,你会得到好的和坏的。如果你不能在MyObjectBase
没有对象实现的情况下创建IMyRequiredInterface
,你也不能在没有这样的对象的情况下创建子类。
So what do you do when someone doesn't hand you that. Do you have a default?
那么当有人不给你时你会怎么做。你有默认吗?
It's quite reasonable for a subclass to instantiate something that implements IMyRequiredInterface
, and pass that to the superclass constructor with a super(...)
call. Can you do that? (Though, as I recall, you can get a bit hung up on this in Java, having to call super
before doing anything else....)
子类实例化实现 的东西IMyRequiredInterface
,并通过super(...)
调用将其传递给超类构造函数是非常合理的。你能做到吗?(不过,正如我所记得的,在 Java 中你可能会有点挂断这一点,super
在做任何其他事情之前必须先调用......)
回答by Darin Dimitrov
There's a code smell here. If you inherit from a class that has a parameterless constructor it means that the author of this base class intended that it cannot function properly without supplying the necessary dependency. If you inherit from it and call a base method that required this dependency your code will probably fail if the dependency is not supplied. So if you really think that you should completely override this behavior you don't have to inherit from this base class, otherwise just copy the constructor in the inherited class.
这里有一种代码气味。如果您从具有无参数构造函数的类继承,则意味着此基类的作者打算在不提供必要依赖项的情况下使其无法正常运行。如果您从它继承并调用需要此依赖项的基本方法,如果未提供该依赖项,您的代码可能会失败。因此,如果您真的认为应该完全覆盖此行为,则不必从该基类继承,否则只需复制继承类中的构造函数即可。
回答by bashmohandes
What about providing a protected constructor in the base class that takes no paramters?
在基类中提供一个不带参数的受保护构造函数怎么样?
class MyBase
{
readonly int _x;
public MyBase(int x)
{
_x = x;
}
protected MyBase()
{
_x = 0;
}
}
class MyChild : MyBase
{
public MyChild()
{
}
}
回答by jmservera
I would do that:
我会这样做:
public class AnotherObject:MyObjectBase
{
public AnotherObject():MyObjectBase(new RequiredInterfaceImplementation())
{
}
}
Where:
在哪里:
public class RequiredInterfaceImplementation:IMyRequiredInterface
{
... your implementation
}
回答by Yitzchok
Most DI frameworks have the functionality to inject services into properties (Property Setter Injection) using Attributes so you can try that.
大多数 DI 框架都具有使用属性将服务注入属性(属性设置器注入)的功能,因此您可以尝试一下。
You can subclass but the subclass will have to know how to create or get the Interface Implementation (using the ServiceLocator or something).
您可以子类化,但子类必须知道如何创建或获取接口实现(使用 ServiceLocator 或其他东西)。
From the DI's point of view it doesn't have anything to fulfill because the class only has an empty constructor (most use the constructor with the most params) and no attributes telling him to do anything else.
从 DI 的角度来看,它没有任何东西要完成,因为该类只有一个空的构造函数(大多数使用具有最多参数的构造函数)并且没有属性告诉他做任何其他事情。
回答by Sudherson Vetrichelvan
I had the same scenario where my base (concrete) class and the child class had a dependency, I was worried if these are different instances.
我有相同的场景,我的基础(具体)类和子类有依赖关系,我担心这些是不同的实例。
But, Autofac (I believe other container tools too) has .InstancePerRequest() which will share the same instance per Http request.
但是,Autofac(我相信其他容器工具也是如此)有 .InstancePerRequest() 它将为每个 Http 请求共享相同的实例。
builder.RegisterType().As().InstancePerRequest();
builder.RegisterType().As().InstancePerRequest();