Unity:告诉容器在注册类型时始终使用接口的特定实现
Unity: tell container to always use specific implementation of an interface when registering a type
我将 运行 保留在这种情况下:假设我有接口 IFoo
和多个实现,例如 RedFoo : IFoo
和 BlackFoo : IFoo
。然后我有 类 在构造函数中采用 IFoo
:
class BlackFooUser
{
public BlackFooUser(IFoo foo, other_parameters_here) {...}
}
class RedFooUser
{
public RedFooUser(IFoo foo, other_parameters_here) {...}
}
如何告诉容器像往常一样解析所有其他参数,但在构造BlackFooUser
时始终使用BlackFoo
,而在构造RedFooUser
时始终使用RedFoo
?我知道我可以在调用 Resolve()
时使用 ParameterOverride
,但我希望它在解析 Red/BlackFooUser
时相同,所以这应该进入 RegisterType
或 RegisterFactory
.
我可以做类似
container.RegisterFactory<RedFooUser>(c=>new RedFooUser(c.Resolve<RedFoo>(), other_parameters_here));
但这很冗长,每次我添加新参数时都必须更改。
有没有更好的方法?
UPDATE 我特别希望通过容器注册来做到这一点,而不修改所涉及的 类。这有多种原因,但归结为:
- 在 类 中编码依赖信息违反了关注点分离
- 在许多 类 和许多依赖项
的情况下,它的扩展性通常很差
- 它限制了 类 的组合方式
- 它限制我类我拥有源代码并可以随意修改
使用抽象 class 和泛型强制指定类型。
Unity 会自动解析具体类型,所以你不需要注册这些。
public abstract class FooUser<TFoo> where TFoo : IFoo
{
private readonly TFoo _foo;
public FooUser(TFoo foo, other parameters)
{
_foo = foo;
}
}
public class BlackFooUser : FooUser<BlackFoo>
{
public BlackFooUser (BlackFoo foo, other parameters)
: base(foo, other parameters)
{
}
}
public class RedFooUser : FooUser<RedFoo>
{
public RedFooUser (RedFoo foo, other parameters)
: base(foo, other parameters)
{
}
}
下面的完整复制 - 输出是:
Constructed RedFooUser with foo 'RedFoo' and otherParameter 'I'm the other parameter'
Constructed BlackFooUser with foo 'BlackFoo' and otherParameter 'I'm the other parameter'
void Main()
{
var container = new UnityContainer()
.RegisterInstance<string>("I'm the other parameter");
var foo1 = container.Resolve<RedFooUser>();
var foo2 = container.Resolve<BlackFooUser>();
}
// Define other methods, classes and n
public interface IFoo
{
}
public class BlackFoo : IFoo { }
public class RedFoo : IFoo { }
public abstract class FooUser<TFoo> where TFoo : IFoo
{
private readonly TFoo _foo;
public FooUser(TFoo foo, string otherParameter)
{
_foo = foo;
Console.WriteLine($"Constructed {GetType().Name} with foo '{foo.GetType().Name}' and otherParameter '{otherParameter}'");
}
}
public class BlackFooUser : FooUser<BlackFoo>
{
public BlackFooUser(BlackFoo foo, string otherParameter)
: base(foo, otherParameter)
{
}
}
public class RedFooUser : FooUser<RedFoo>
{
public RedFooUser(RedFoo foo, string otherParameter)
: base(foo, otherParameter)
{
}
}
当你注册你的类型时,你可以给它们一个名字,然后在注入这些类型的构造函数中引用这个名字。像这样:
public class BlackFoo : IFoo
{
public const string UNITY_KEY = "BlackFoo";
}
在您的容器注册中:
_container.RegisterType<IFoo, BlackFoo>(BlackFoo.UNITY_KEY, new ContainerControlledLifetimeManager());
在你的构造函数中:
public class BlackFooUser
{
public BlackFooUser([Dependency(BlackFoo.UNITY_KEY)] IFoo foo)
{
}
}
这确保当容器进行依赖注入时,它将使用指定的 IFoo
注册。
我将 an issue 提交到 UnityContainer 存储库,Eugene Sadovoy 的回复促使我做出这个答案。
为了避免无限循环,可以将默认工厂注册为命名注册,并从默认的未命名工厂调用它,方法如下(抱歉,与问题相比,我稍微更改了名称):
container
.RegisterType<SpecialFooUser>("stdreg")
.RegisterFactory<SpecialFooUser>(
c => c.Resolve<SpecialFooUser>("stdreg",
new DependencyOverride<IFoo>(c.Resolve<SpecialFoo>()))
);
这可行,但看起来很冗长,所以我写了一些扩展方法和 类(总共约 100 行代码)以使其不那么冗长而更具表现力:
container.Register(
new CustomFactory<SpecialFooUser>()
.DependencyOverride<IFoo, SpecialFoo>());
完整源码在GitHub:https://github.com/ikriv-samples/UnityResolveOverrideFactory
我将 运行 保留在这种情况下:假设我有接口 IFoo
和多个实现,例如 RedFoo : IFoo
和 BlackFoo : IFoo
。然后我有 类 在构造函数中采用 IFoo
:
class BlackFooUser
{
public BlackFooUser(IFoo foo, other_parameters_here) {...}
}
class RedFooUser
{
public RedFooUser(IFoo foo, other_parameters_here) {...}
}
如何告诉容器像往常一样解析所有其他参数,但在构造BlackFooUser
时始终使用BlackFoo
,而在构造RedFooUser
时始终使用RedFoo
?我知道我可以在调用 Resolve()
时使用 ParameterOverride
,但我希望它在解析 Red/BlackFooUser
时相同,所以这应该进入 RegisterType
或 RegisterFactory
.
我可以做类似
container.RegisterFactory<RedFooUser>(c=>new RedFooUser(c.Resolve<RedFoo>(), other_parameters_here));
但这很冗长,每次我添加新参数时都必须更改。
有没有更好的方法?
UPDATE 我特别希望通过容器注册来做到这一点,而不修改所涉及的 类。这有多种原因,但归结为:
- 在 类 中编码依赖信息违反了关注点分离
- 在许多 类 和许多依赖项 的情况下,它的扩展性通常很差
- 它限制了 类 的组合方式
- 它限制我类我拥有源代码并可以随意修改
使用抽象 class 和泛型强制指定类型。
Unity 会自动解析具体类型,所以你不需要注册这些。
public abstract class FooUser<TFoo> where TFoo : IFoo
{
private readonly TFoo _foo;
public FooUser(TFoo foo, other parameters)
{
_foo = foo;
}
}
public class BlackFooUser : FooUser<BlackFoo>
{
public BlackFooUser (BlackFoo foo, other parameters)
: base(foo, other parameters)
{
}
}
public class RedFooUser : FooUser<RedFoo>
{
public RedFooUser (RedFoo foo, other parameters)
: base(foo, other parameters)
{
}
}
下面的完整复制 - 输出是:
Constructed RedFooUser with foo 'RedFoo' and otherParameter 'I'm the other parameter' Constructed BlackFooUser with foo 'BlackFoo' and otherParameter 'I'm the other parameter'
void Main()
{
var container = new UnityContainer()
.RegisterInstance<string>("I'm the other parameter");
var foo1 = container.Resolve<RedFooUser>();
var foo2 = container.Resolve<BlackFooUser>();
}
// Define other methods, classes and n
public interface IFoo
{
}
public class BlackFoo : IFoo { }
public class RedFoo : IFoo { }
public abstract class FooUser<TFoo> where TFoo : IFoo
{
private readonly TFoo _foo;
public FooUser(TFoo foo, string otherParameter)
{
_foo = foo;
Console.WriteLine($"Constructed {GetType().Name} with foo '{foo.GetType().Name}' and otherParameter '{otherParameter}'");
}
}
public class BlackFooUser : FooUser<BlackFoo>
{
public BlackFooUser(BlackFoo foo, string otherParameter)
: base(foo, otherParameter)
{
}
}
public class RedFooUser : FooUser<RedFoo>
{
public RedFooUser(RedFoo foo, string otherParameter)
: base(foo, otherParameter)
{
}
}
当你注册你的类型时,你可以给它们一个名字,然后在注入这些类型的构造函数中引用这个名字。像这样:
public class BlackFoo : IFoo
{
public const string UNITY_KEY = "BlackFoo";
}
在您的容器注册中:
_container.RegisterType<IFoo, BlackFoo>(BlackFoo.UNITY_KEY, new ContainerControlledLifetimeManager());
在你的构造函数中:
public class BlackFooUser
{
public BlackFooUser([Dependency(BlackFoo.UNITY_KEY)] IFoo foo)
{
}
}
这确保当容器进行依赖注入时,它将使用指定的 IFoo
注册。
我将 an issue 提交到 UnityContainer 存储库,Eugene Sadovoy 的回复促使我做出这个答案。
为了避免无限循环,可以将默认工厂注册为命名注册,并从默认的未命名工厂调用它,方法如下(抱歉,与问题相比,我稍微更改了名称):
container
.RegisterType<SpecialFooUser>("stdreg")
.RegisterFactory<SpecialFooUser>(
c => c.Resolve<SpecialFooUser>("stdreg",
new DependencyOverride<IFoo>(c.Resolve<SpecialFoo>()))
);
这可行,但看起来很冗长,所以我写了一些扩展方法和 类(总共约 100 行代码)以使其不那么冗长而更具表现力:
container.Register(
new CustomFactory<SpecialFooUser>()
.DependencyOverride<IFoo, SpecialFoo>());
完整源码在GitHub:https://github.com/ikriv-samples/UnityResolveOverrideFactory