C# 如何为应用程序结构中的所有类注入足够的信息
所以,我正试图(但似乎失败了)让我的头围绕DI 我知道我应该编写我的控件/类,以便传入适当的接口,IoC容器将为我解决问题 我可以看到这对MVC控制器是如何工作的。我不实例化它,系统将向它注入我在构造函数中包含的任何依赖项 但接下来会发生什么呢 我的控制器实例化一个类(C# 如何为应用程序结构中的所有类注入足够的信息,c#,asp.net-mvc,dependency-injection,inversion-of-control,unity-container,C#,Asp.net Mvc,Dependency Injection,Inversion Of Control,Unity Container,所以,我正试图(但似乎失败了)让我的头围绕DI 我知道我应该编写我的控件/类,以便传入适当的接口,IoC容器将为我解决问题 我可以看到这对MVC控制器是如何工作的。我不实例化它,系统将向它注入我在构造函数中包含的任何依赖项 但接下来会发生什么呢 我的控制器实例化一个类(ClassA),该类实例化一个需要(比如)存储库的类(ClassB) 自动取款机,我的代码看起来像 public class ClassB { private IMyRepo repo; public ClassB
ClassA
),该类实例化一个需要(比如)存储库的类(ClassB
)
自动取款机,我的代码看起来像
public class ClassB
{
private IMyRepo repo;
public ClassB()
{
repo = DependencyResolver.Current.GetService<IMyRepo>();
// ...
}
}
我的问题是,这意味着我将直接或通过工厂向控制器注入内容),控制器不应该知道任何信息(在本例中是回购协议),这感觉更加错误
我无法解决如何才能同时防止系统的某些部分暴露在不应该暴露的地方
如果有人能帮助我充分理解整个DI,我将不胜感激,这样我就可以解决我的困境,或者解释为什么我不能吃蛋糕,你可以让IoC容器将ClassA的实现注入控制器。如果这样做,就不需要将IMyRepo提供给ClassA 当然,这需要ClassA实现一个接口,并向容器注册它 如果您不希望容器向您提供ClassA,另一种可能的方法是让ClassA请求服务定位器来解决它的依赖关系
public class ClassA
{
IMyRepo myRepo;
public ClassA()
{
myRepo = Container.Resolve<IMyRepo>();
}
public void DoSomething()
{
var classB = new ClassB(myRepo);
// ...
}
}
公共类ClassA
{
IMyRepo myRepo;
公共甲级()
{
myRepo=Container.Resolve();
}
公共无效剂量测定法()
{
var类别B=新类别B(myRepo);
// ...
}
}
这是可行的,但是服务定位器模式被认为是反模式。我建议所有依赖项都针对一个接口进行编程。如果您使用的是IOC容器,那么您可以从链的最顶端利用它,例如示例中的MVC控制器。假设您的容器能够成功构建所有依赖项,那么控制器将不知道
ClassB
你的问题是部分采用国际奥委会。假设ClassA
是一个“服务”类,那么在索引()中新建它是没有意义的
通常情况下,它更类似于:
public class MyController : MyController
{
private IMyRepo myrepo;
public MyController(IMyRepo myRepo)
{
this.myRepo = myRepo;
}
public ActionResult Index()
{
myrepo.DoSomething()
}
}
或
如果您关心的是,当我在不使用ClassA
的Post()
上时,我为什么要构造ClassA
这是Index()
所需要的。这通常通过注射工厂来解决。大多数IOC容器都支持这种开箱即用的方式
public class MyController : MyController
{
private IMyRepo myrepo;
private Func<ClassA> aFactory;
public MyController(IMyRepo myRepo, Func<ClassA> aFactory)
{
this.myRepo = myRepo;
this.aFactory = aFactory;
}
public ActionResult Index()
{
var classA = aFactory.Invoke();
classA.DoSomething()
}
}
公共类MyController:MyController
{
私人IMyRepo myrepo;
私人Func工厂;
公共MyController(IMyRepo myRepo,Func工厂)
{
this.myRepo=myRepo;
this.aFactory=aFactory;
}
公共行动结果索引()
{
var classA=aFactory.Invoke();
classA.DoSomething()
}
}
如果您不实际使用ClassA,则无需支付任何构建成本
控制器应该有几个参数,对于所有实例化的“服务”都是一样的。如果您发现需要具有5、7、12和更多依赖项的构造函数,这表明系统设计不好。只向类中注入它们需要的:
public class MyController : MyController
{
private ClassA classA;
public MyController(ClassA classA)
{
this.classA = classA;
}
public ActionResult Index()
{
classA.DoSomething()
//...
}
}
public class ClassA
{
private ClassB classB;
public ClassA(ClassB classB)
{
this.classB = classB;
}
public void DoSomething()
{
// ...
}
}
public class ClassB
{
private IMyRepo repo;
public ClassB(IMyRepo myRepo)
{
this.myRepo = myRepo;
}
}
在应用程序中,您可以组成整个对象图:
var ctrl =
new MyController(
new ClassA(
new ClassB(
new MyRepo())));
服务定位器不是反模式。在您的示例中,服务位置的具体用法是一种反模式。我可能过于简化了。我的控制器调用一个BL类,该类反过来可能引用DAL中的一个或多个repo。我不希望其他开发者走捷径,直接从UI(即控制器)中访问回购协议;我希望他们使用BL,BL将访问适当的回购协议。如果我必须通过回购工厂进入市场,我看不出如何防止这种情况Controller@StuartHemming-为您的BL提供一个接口IClassA、IClassB,并将其注入MyControllerinstead@StuartHemming您几乎无法阻止开发人员绕过您的系统设计。这可以通过教育和代码审查来解决。无论您如何精心地尝试使用访问修饰符,我仍然可以通过反射将其引入。访问修饰符只是建议。@mike123这对停止新imusingthesisclasses没有任何作用(太糟糕了,太悲伤了)
因此,本质上,我需要创建两个工厂;一个用于所有BL类,另一个用于所有REPO,并将它们全部注入控制器的构造函数中。我猜这将意味着,每当我实例化一个新的BL类时,我都必须传入Repo工厂,这样它才能完成它的任务。可能的重复:我使用的是Unity,所以你是否建议UnityConfig是我需要编写图表的地方?我还假设在实际代码中,所有构造函数都应该,至少在可能的情况下,将接口作为参数。@StuartHemming在应用程序的。您可以使用Unity来实现这一点,但我建议改为使用Unity。您的构造函数可以采用多态或。
public class MyController : MyController
{
private ClassA classA;
public MyController(ClassA classA)
{
this.classA = classA;
}
public ActionResult Index()
{
classA.DoSomething()
//...
}
}
public class ClassA
{
private ClassB classB;
public ClassA(ClassB classB)
{
this.classB = classB;
}
public void DoSomething()
{
// ...
}
}
public class ClassB
{
private IMyRepo repo;
public ClassB(IMyRepo myRepo)
{
this.myRepo = myRepo;
}
}
var ctrl =
new MyController(
new ClassA(
new ClassB(
new MyRepo())));