public class Program { //Entrypoint
public static void Main(string[] args) {
var container = new UnityContainer();
container.RegisterType<IMetric>(new InjectionFactory(c => BuildMetric()));
...
SomeClassThatCallsLoader kk = new SomeClassThatCallsLoader();
kk.DoSomething(); //Loader gets instantiated in here..
}
}
public class Loader {
[Dynamic]
public IMetric Metric { get; set;}
}
为什么未设置Metric属性?控制台应用程序。我必须注册容器吗?在哪里以及如何?
答案 0 :(得分:1)
依赖注入容器(例如Unity)没有任何作用-它们通过在容器中解析实例及其依赖来工作。这意味着所有类型都必须在容器中注册(显式或使用约定)。
// Composition Root
var container = new UnityContainer();
container.RegisterFactory<IMetric>(c => BuildMetric());
container.RegisterType<ILoader, Loader>();
container.RegisterType<ISomeClassThatDependsOnLoader, SomeClassThatDependsOnLoader>();
推荐的注入依赖项的方法是通过类构造函数接受它们,而不是使用属性注入。仅在合理时才使用属性注入。
但这是您的示例,重写后既包含属性注入也包含构造函数注入,还包含工厂方法(在此处仅是静态的,因为您未提供如何执行此操作的示例-我不建议使用静态方法(如果可以避免的话)。
using System;
using Unity;
class Program
{
static void Main(string[] args)
{
// Composition Root
var container = new UnityContainer();
container.RegisterFactory<IMetric>(c => BuildMetric());
container.RegisterType<ILoader, Loader>();
container.RegisterType<ISomeClassThatDependsOnLoader, SomeClassThatDependsOnLoader>();
// Application (runtime)
var kk = container.Resolve<ISomeClassThatDependsOnLoader>(); //Loader gets instantiated in here..
kk.DoSomething();
}
public static IMetric BuildMetric()
{
return new Metric();
}
}
public interface ILoader
{
IMetric Metric { get; set; } // Property Injection
}
public class Loader : ILoader
{
[Dependency]
public IMetric Metric { get; set; }
}
public interface IMetric
{
}
public class Metric : IMetric
{
}
public interface ISomeClassThatDependsOnLoader
{
void DoSomething();
}
public class SomeClassThatDependsOnLoader : ISomeClassThatDependsOnLoader
{
private readonly ILoader loader;
public SomeClassThatDependsOnLoader(ILoader loader) // Constructor Injection
{
this.loader = loader ?? throw new ArgumentNullException(nameof(loader));
}
public void DoSomething()
{
// Do something with this.loader.Metric...
}
}
因此,您的属性注入示例有两个问题:
Loader
类型。[Dependency]
,而不是[Dynamic]
。请注意,由于所有依赖IMetric
的类型都应引用ILoader
而不是Loader
的引用(否则它不能被交换或嘲笑)。但是,如果依赖ILoader
的类需要访问IMetric
,则ILoader
必须公开IMetric
作为其接口的一部分。我不建议您像上面那样做,将IMetric
注入依赖于它的每个类的类构造函数会更有意义。我只是在做上述操作,向您展示属性注入的工作原理,但这并不是我在大多数情况下建议的设计选择。
以下是使用“常规”依赖项注入技术的示例:
using System;
using Unity;
class Program
{
static void Main(string[] args)
{
// Composition Root
var container = new UnityContainer();
container.RegisterType<IMetric, Metric>();
container.RegisterType<IApplication, Application>();
// Application (runtime)
// Note that in a console application, you generally only call
// container.Resolve() once followed by a method to set things
// in motion. The type you resolve here should represent the
// ENTIRE console application, and you would typically pass
// the args (if used) through to that class to process them.
// No business logic should go here, only code to read config files,
// register types, and set the application in motion.
var app = container.Resolve<IApplication>(); // Application and Metric get instantiated here...
app.Run(args);
}
}
public interface IMetric
{ }
public class Metric : IMetric
{ }
public interface IApplication
{
void Run(string[] args);
}
public class Application : IApplication
{
private readonly IMetric metric;
public Application(IMetric metric) // Constructor Injection
{
this.metric = metric ?? throw new ArgumentNullException(nameof(metric));
}
public void Run(string[] args)
{
// Do something with this.metric...
}
}
请注意,如果使用构造函数注入,则可以完全消除Loader
类型(假设您可以不使用它)。您还可以删除factory方法,这使代码更简单。