我正在尝试注册同一接口(interface)的多个实现...然后...使用 Setter 在我的 Application 实例上设置属性。我已经尝试了多个在线示例,并且总是将相同的实例插入到 2 个应用程序属性中。
- 注意:我试过很多网上的例子,下面是最新的版本
例如……
当我在 Quick Watch 中查看应用程序对象时,我得到以下信息
我的配置:
显然,我已经解析出所有其他对象...
public ContainerRegistry()
{
Scan(
scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.LookForRegistries();
scan.AssembliesFromApplicationBaseDirectory(f => f.FullName.StartsWith("Demo.Common", true, null));
scan.AssembliesFromApplicationBaseDirectory(f => f.FullName.StartsWith("XXX.XXX.MeasurementContracts", true, null));
scan.AddAllTypesOf(typeof(IMeasurementContractsApplication));
scan.AddAllTypesOf(typeof(IInstanceProvider));
scan.SingleImplementationsOfInterface();
});
// --------
// NAMED INSTANCES - IInstanceProvider
For<IInstanceProvider>().Use<DistributionListProvider>();
For<IInstanceProvider>().Add<FirstDeliveryNoticeDocumentRecallManager>().Named("firstDeliveryNoticeDocumentRecallManager");
// --------
// APPLICATION
For<IMeasurementContractsApplication>().Use<MeasurementContractsApplication>()
// Component
.Setter(x => x.DistributionListProvider).Is<DistributionListProvider>()
.Setter(x => x.FirstDeliveryNoticeDocumentRecallManager).IsNamedInstance("firstDeliveryNoticeDocumentRecallManager");
}
应用示例:
显然,我已经解析出所有其他对象...
public class MeasurementContractsApplication : IMeasurementContractsApplication
{
[SetterProperty]
public IMeasurementContractsUnitOfWork UnitOfWork { get; set; }
[SetterProperty]
public IInstanceProvider DistributionListProvider { get; set; }
[SetterProperty]
public IInstanceProvider FirstDeliveryNoticeDocumentRecallProvider { get; set; }
}
IInstanceProvider 的:
public class DistributionListProvider : ProviderBase, IInstanceProvider
{
// Purposely left-out Properties, Methods etc.
}
public class FirstDeliveryNoticeDocumentAdminUpdateProvider : ProviderBase, IInstanceProvider
{
// Purposely left-out Properties, Methods etc.
}
public class ProviderBase
{
[SetterProperty]
public IMeasurementContractsUnitOfWork UnitOfWork { get; set; }
}
----------------------------------------
更新:来自向我提出的问题
为了将事情降低到极其基本的水平......我决定实现一组最小的 2 个类来尝试建议:
public interface ITesting
{
string Name();
}
public class Foo : ITesting
{
public string Name()
{
return string.Empty;
}
}
public class Bar : ITesting
{
public string Name()
{
return string.Empty;
}
}
public ContainerRegistry()
{
Scan(
scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.LookForRegistries();
scan.AssembliesFromApplicationBaseDirectory(f => f.FullName.StartsWith("Demo.Common", true, null));
scan.AssembliesFromApplicationBaseDirectory(f => f.FullName.StartsWith("XXX.MeasurementContracts", true, null));
scan.AddAllTypesOf(typeof(IMeasurementContractsApplication));
scan.AddAllTypesOf(typeof(IManager<>));
scan.AddAllTypesOf(typeof(IDocumentDependency));
scan.AddAllTypesOf(typeof(IDataItemProviderFor<>));
scan.AddAllTypesOf(typeof(IDatasetBuilderFor<>));
scan.AddAllTypesOf(typeof(IXmlTransformerFor<>));
scan.AddAllTypesOf(typeof(IWorkflowProvider));
scan.AddAllTypesOf(typeof(IInstanceProvider));
scan.AddAllTypesOf(typeof(IPdfConverterClient));
scan.AddAllTypesOf(typeof(IReportFor<>));
scan.AddAllTypesOf(typeof(IAdminUpdateCommandFor<>));
scan.AddAllTypesOf(typeof(ITesting));
scan.SingleImplementationsOfInterface();
});
Component Providers
For<IMeasurementContractsApplication>().Use<MeasurementContractsApplication>()
Setter(x => x.Bar).Is<Bar>()
Setter(x => x.Foo).Is<Foo>();
}
总是会发生两种结果之一
- 属性为NULL
- 我收到以下错误消息
"No default Instance is registered and cannot be automatically determined for type 'IInstanceProvider' No default instance is specified."
问:目标实现位于何处?
XXX.MeasurementContracts.Business
包含“ContainerRegistry”和所有类、接口(interface)等。
XXX.MeasurementContracts.Web
包含“StructuremapMvcConfig”、“IoC”初始化器和它自己的“DefaultRegistry”
MeasurementContracts.UnitTests
在其“IoC”初始值设定项中添加业务“ContainerRegistry”...然后添加其自己的“ContainerRegistry”。
尝试:尝试命名注册 我将以下内容添加到“ContainerRegistry”,同时,两者都被填充了......它们的类型为“Bar”
// Component Providers
For<ITesting>().Use<Bar>().Named("Bar");
For<ITesting>().Add<Foo>().Named("Foo");
// Component Providers
For<IMeasurementContractsApplication>().Use<MeasurementContractsApplication>()
.Setter(x => x.Bar).Is<Bar>()
.Setter(x => x.Foo).Is<Foo>();
如何解决“Foo”? 我也试过 ".Setter(x => x.Foo).Is(c => c.GetInstance("Foo"));"
分析:使用 container.WhatDoIHave() 好的,使用“WhatDoIHave”显示我已正确配置“ITesting”实例。
- transient - XXX.MeasurementContracts.Business.Providers.Bar('bar') - bar(默认)
- transient - XXX.MeasurementContracts.Business.Providers.Foo('foo') - foo
如何将“Foo”和“Bar”分解为各自的属性?
最佳答案
删除 DistributionListProvider
和 FirstDeliveryNoticeDocumentRecallProvider
属性的显式 setter 属性。
Explicit Setter Injection with [SetterProperty] Attributes
Without the
[SetterProperty]
attributes decorating the setters, StructureMap would ignore theDistributionListProvider
andFirstDeliveryNoticeDocumentRecallProvider
properties when it builds up aMeasurementContractsApplication
object. With the attributes, StructureMap will try to build and attach values for the two properties as part of object construction.
public class MeasurementContractsApplication : IMeasurementContractsApplication {
[SetterProperty]
public IMeasurementContractsUnitOfWork UnitOfWork { get; set; }
public IInstanceProvider DistributionListProvider { get; set; }
public IInstanceProvider FirstDeliveryNoticeDocumentRecallProvider { get; set; }
}
并且由于它无法区分哪个接口(interface)用于哪个属性,因此它将第一个注册的接口(interface)应用于两个属性。
这就是为什么在这种情况下,您应该直接应用内联 setter
Inline Setter Configuration
Any setter property not configured with
[SetterProperty]
or the setter policies in the next section can still be filled by StructureMap if an inline dependency is configured matching that setter property as shown in the example below:
For<IMeasurementContractsApplication>()
.Use<MeasurementContractsApplication>()
// Component
.Setter(x => x.DistributionListProvider)
.Is<DistributionListProvider>()
.Setter(x => x.FirstDeliveryNoticeDocumentRecallManager)
.Is<FirstDeliveryNoticeDocumentAdminUpdateProvider>();
以下最小完整且可验证的示例演示了上述内容并在测试时通过。
namespace StructureMap.Unit_Tests.Misc {
[TestClass]
public class StructureMapTests {
[TestMethod]
public void _Inline_Setter_Should_Populate_Multiple_Implementations() {
//Arrange
var registry = new StructureMap.Registry();
registry.IncludeRegistry<ContainerRegistry>();
// build a container
var container = new StructureMap.Container(registry);
//Act
var application = container.GetInstance<IMeasurementContractsApplication>();
//Assert
application.Should().NotBeNull();
application.Foo.Should().BeOfType<Foo>();
application.Bar.Should().BeOfType<Bar>();
}
}
class ContainerRegistry : StructureMap.Registry {
public ContainerRegistry() {
Scan(
scan => {
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.LookForRegistries();
scan.AssembliesFromApplicationBaseDirectory(f => f.FullName.StartsWith("Demo.Common", true, null));
scan.AssembliesFromApplicationBaseDirectory(f => f.FullName.StartsWith("XXX.MeasurementContracts", true, null));
scan.AddAllTypesOf(typeof(IMeasurementContractsApplication));
scan.AddAllTypesOf(typeof(ITesting));
scan.SingleImplementationsOfInterface();
});
//Component Providers
For<IMeasurementContractsApplication>()
.Use<MeasurementContractsApplication>()
.Setter(x => x.Bar)
.Is<Bar>()
.Setter(x => x.Foo)
.Is<Foo>();
}
}
public interface IMeasurementContractsApplication {
ITesting Foo { get; set; }
ITesting Bar { get; set; }
}
public class MeasurementContractsApplication : IMeasurementContractsApplication {
public ITesting Foo { get; set; }
public ITesting Bar { get; set; }
}
public interface ITesting {
string Name();
}
public class Foo : ITesting {
public string Name() {
return string.Empty;
}
}
public class Bar : ITesting {
public string Name() {
return string.Empty;
}
}
}
关于c# - 为同一接口(interface)的多个实现设置属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50802502/