在控制台应用中使用 Unity 属性 [动态] 进行属性注入不起作用


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

为什么没有设置指标属性?控制台应用。我必须注册容器吗?在哪里以及如何?

依赖注入容器(如 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...
}
}

因此,您的属性注入示例有 2 个问题:

  1. 您没有向 Unity 容器注册Loader类型。
  2. 您使用了错误的属性。它应该是[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类型(假设可以不使用它)。您还可以删除工厂方法,这使代码更简单。

最新更新