代码之家  ›  专栏  ›  技术社区  ›  Prisoner ZERO

为同一接口的多个实现设置属性

  •  4
  • Prisoner ZERO  · 技术社区  · 7 年前

    我试图注册同一接口的多个实现…然后…使用setter在我的应用程序实例上设置属性。我尝试过多个在线示例,总是将同一个实例插入到2个应用程序属性中。

    • 注:我在网上试过很多例子,下面只是最新版本

    例如。。。
    当我在快速监视中查看应用程序对象时,会得到以下信息

    enter image description here

    我的配置:
    很明显,我已经分析了所有其他的物体…

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

    两种结果中的一种总是会发生

    1. 属性为空
    2. 我收到以下错误消息

    “未注册默认实例,并且无法自动 为类型“iInstanceProvider”确定没有默认实例 指定。”

    问:目标实现位于何处?

    XXX.测量合同.业务
    包含“containerRegistry”和所有类、接口等。

    xxx.measurementcontracts.web网站
    包含“structuremapmvcconfig”、“ioc”初始值设定项及其自己的“defaultregistry”

    测量合同.单元试验
    将业务“containerRegistry”添加到其“ioc”初始值设定项中…然后添加自己的“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”实例。

    • 瞬态-xxx.measurementcontracts.business.providers.bar('bar')-bar(默认)
    • 瞬态-xxx.measurementcontracts.business.providers.foo('foo')-foo

    如何将“foo”和“bar”分解为它们各自的属性?

    1 回复  |  直到 7 年前
        1
  •  1
  •   Nkosi    7 年前

    移除的显式setter属性 DistributionListProvider FirstDeliveryNoticeDocumentRecallProvider 性质。

    Explicit Setter Injection with [SetterProperty] Attributes

    没有 [SetterProperty] 修饰setters的属性,structuremap将忽略 分发列表提供程序 首次交付通知文档中心调用提供程序 当它生成 MeasurementContractsApplication 对象。使用这些属性,structuremap将尝试为这两个属性构建和附加值,作为对象构造的一部分。

    public class MeasurementContractsApplication : IMeasurementContractsApplication {
        [SetterProperty]
        public IMeasurementContractsUnitOfWork UnitOfWork { get; set; }
    
    
        public IInstanceProvider DistributionListProvider { get; set; }
    
    
        public IInstanceProvider FirstDeliveryNoticeDocumentRecallProvider { get; set; }
    }
    

    而且由于它无法区分要为哪个属性使用哪个接口,因此它将第一个注册的接口应用于这两个属性。

    这就是为什么,在本例中,您应该只在内联中应用setters

    Inline Setter Configuration

    任何未配置的setter属性 [设置属性] 或者,如果内联依赖项被配置为匹配SETER属性,那么在下一节中的SETER策略仍然可以由结构图填充,如下面的示例所示:

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

    Quick watch