如何根据最终注入链目标注入实例?
How to inject instance depending on the final injection chain target?
我有 classes:X1 <- Y <- Z <- Config
(箭头表示通过构造函数注入)和 X2 <- Y <- Z <- Config
。 Z
需要一些配置(Config
class),但实例取决于最终类型:X1
和 X2
(类型本身或它们定义的键不知何故)。在此示例中,每个 Y
、Z
和 Config
class.
应该有两个不同的实例
如何根据最终使用位置(X1
或 X2
)在 Z
中使用不同的 Config
?
class X1
{
public X1(Y y)
{
int c = y.Z.Config.C; // This config variable is connected with X1.
}
}
class X2
{
public X2(Y y)
{
int c = y.Z.Config.C; // This config variable is different than the one for X1.
}
}
class Y
{
public Z Z { get; }
public Y(Z z)
{
Z = z;
}
}
class Z
{
public Config Config { get; }
public Z(Config config)
{
Config = config;
}
}
class Config
{
public int C { get; set; }
}
我可以像下面那样做,但它看起来很腥很臭(一个粗略的例子):
Bind<Config>().ToMethod(x =>
{
// Return proper config object depending on the classes found in the injection chain...
IRequest req = x.Request;
while (req != null)
{
if (req.Service.UnderlyingSystemType == typeof(X1))
{
return configForX1;
}
if (req.Service.UnderlyingSystemType == typeof(X2))
{
return configForX2;
}
req = req.ParentRequest;
}
throw new Exception("Oh no.");
});
或者我应该这样做来减少腥味:
class X1
{
public X1([Named("X1")] Config config, Y y)
{
y.SetConfig(config);
}
}
class Y
{
private readonly Z _z;
public Y(Z z)
{
_z = z;
}
public void SetConfig(Config config)
{
_z.SetConfig(config);
}
}
class Z
{
private Config _config;
public void SetConfig(Config config)
{
_config = config;
}
}
和
Bind<MetricsApiConfiguration>().To().Named("X1");
Bind<MetricsApiConfiguration>().To().Named("X2");
还有其他(更好的)想法吗?
WhenInjectedInto
很接近,但如您所述,仅查看当前请求。我创建了一个扩展方法来解决这个确切的用例:
public static IBindingInNamedWithOrOnSyntax<T> WhenAnyAncestorIs<T>(this IBindingWhenSyntax<T> binding, params Type[] types)
{
bool Matches(IRequest request)
{
Type target = request.Target?.Member?.ReflectedType;
return (target != null && types.Any(t => t == target))
|| (request.ParentRequest != null && Matches(request.ParentRequest));
}
return binding.When(Matches);
}
并像这样使用:
Bind<IConfigSource>().To<DataConfigSource>()
.WhenAnyAncestorIs(
typeof(DataConfigurationRepository),
typeof(ManifestRepository),
typeof(DataManager)
)
.InSingletonScope();
对于不使用这些类型的请求,您将需要一个额外的绑定。
我有 classes:X1 <- Y <- Z <- Config
(箭头表示通过构造函数注入)和 X2 <- Y <- Z <- Config
。 Z
需要一些配置(Config
class),但实例取决于最终类型:X1
和 X2
(类型本身或它们定义的键不知何故)。在此示例中,每个 Y
、Z
和 Config
class.
如何根据最终使用位置(X1
或 X2
)在 Z
中使用不同的 Config
?
class X1
{
public X1(Y y)
{
int c = y.Z.Config.C; // This config variable is connected with X1.
}
}
class X2
{
public X2(Y y)
{
int c = y.Z.Config.C; // This config variable is different than the one for X1.
}
}
class Y
{
public Z Z { get; }
public Y(Z z)
{
Z = z;
}
}
class Z
{
public Config Config { get; }
public Z(Config config)
{
Config = config;
}
}
class Config
{
public int C { get; set; }
}
我可以像下面那样做,但它看起来很腥很臭(一个粗略的例子):
Bind<Config>().ToMethod(x =>
{
// Return proper config object depending on the classes found in the injection chain...
IRequest req = x.Request;
while (req != null)
{
if (req.Service.UnderlyingSystemType == typeof(X1))
{
return configForX1;
}
if (req.Service.UnderlyingSystemType == typeof(X2))
{
return configForX2;
}
req = req.ParentRequest;
}
throw new Exception("Oh no.");
});
或者我应该这样做来减少腥味:
class X1
{
public X1([Named("X1")] Config config, Y y)
{
y.SetConfig(config);
}
}
class Y
{
private readonly Z _z;
public Y(Z z)
{
_z = z;
}
public void SetConfig(Config config)
{
_z.SetConfig(config);
}
}
class Z
{
private Config _config;
public void SetConfig(Config config)
{
_config = config;
}
}
和
Bind<MetricsApiConfiguration>().To().Named("X1");
Bind<MetricsApiConfiguration>().To().Named("X2");
还有其他(更好的)想法吗?
WhenInjectedInto
很接近,但如您所述,仅查看当前请求。我创建了一个扩展方法来解决这个确切的用例:
public static IBindingInNamedWithOrOnSyntax<T> WhenAnyAncestorIs<T>(this IBindingWhenSyntax<T> binding, params Type[] types)
{
bool Matches(IRequest request)
{
Type target = request.Target?.Member?.ReflectedType;
return (target != null && types.Any(t => t == target))
|| (request.ParentRequest != null && Matches(request.ParentRequest));
}
return binding.When(Matches);
}
并像这样使用:
Bind<IConfigSource>().To<DataConfigSource>()
.WhenAnyAncestorIs(
typeof(DataConfigurationRepository),
typeof(ManifestRepository),
typeof(DataManager)
)
.InSingletonScope();
对于不使用这些类型的请求,您将需要一个额外的绑定。