为同一接口的多个实现设置 属性
Setting a Property for Multiple Implementations of the Same Interface
我正在尝试注册同一接口的多个实现...然后...使用 Setter 在我的应用程序实例上设置 属性。我已经尝试了多个在线示例,并且总是将相同的实例插入到 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>();
}
2 个结果中的一个总是会发生
- 属性 为 NULL
- 我收到以下错误消息
"No default Instance is registered and cannot be automatically
determined for type 'IInstanceProvider' No default instance is
specified."
问:目标实现位于何处?
XXX.MeasurementContracts.Business
包含 "ContainerRegistry" 和所有 类、接口等
XXX.MeasurementContracts.Web
包含 "StructuremapMvcConfig"、"IoC" 初始值设定项及其自己的 "DefaultRegistry"
MeasurementContracts.UnitTests
在其 "IoC" 初始值设定项中添加业务 "ContainerRegistry"...然后添加其自己的 "ContainerRegistry"。
ATTEMPT:尝试命名注册
我将以下内容添加到 "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" 个实例。
- 瞬态 - XXX.MeasurementContracts.Business.Providers.Bar('bar') - 条形图(默认)
- 瞬态 - 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 the DistributionListProvider
and FirstDeliveryNoticeDocumentRecallProvider
properties when it builds up a MeasurementContractsApplication
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; }
}
并且由于它无法区分哪个接口用于哪个 属性 它会将第一个注册的接口应用于两个属性。
这就是为什么在这种情况下,您应该直接应用 setters inline
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;
}
}
}
我正在尝试注册同一接口的多个实现...然后...使用 Setter 在我的应用程序实例上设置 属性。我已经尝试了多个在线示例,并且总是将相同的实例插入到 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>();
}
2 个结果中的一个总是会发生
- 属性 为 NULL
- 我收到以下错误消息
"No default Instance is registered and cannot be automatically determined for type 'IInstanceProvider' No default instance is specified."
问:目标实现位于何处?
XXX.MeasurementContracts.Business
包含 "ContainerRegistry" 和所有 类、接口等
XXX.MeasurementContracts.Web
包含 "StructuremapMvcConfig"、"IoC" 初始值设定项及其自己的 "DefaultRegistry"
MeasurementContracts.UnitTests
在其 "IoC" 初始值设定项中添加业务 "ContainerRegistry"...然后添加其自己的 "ContainerRegistry"。
ATTEMPT:尝试命名注册 我将以下内容添加到 "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" 个实例。
- 瞬态 - XXX.MeasurementContracts.Business.Providers.Bar('bar') - 条形图(默认)
- 瞬态 - 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; }
}
并且由于它无法区分哪个接口用于哪个 属性 它会将第一个注册的接口应用于两个属性。
这就是为什么在这种情况下,您应该直接应用 setters inline
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;
}
}
}