【问题标题】:Mixed resolution-time arguments in Castle Windsor温莎城堡中的混合解决时间参数
【发布时间】:2014-03-08 11:26:54
【问题描述】:

我有一个像这样的构造函数,我想从工厂传递参数:

public Event(IRegisteredType registeredEarly, IPassNow passNowByInterface,
                               DateTimeOffset local, DateTimeOffset world)
{
    // ...
}

我尝试了这种方法,但它不起作用,因为本地和世界价值观相同,一个覆盖另一个:

public Event CreateEvent(IPassNow passNow, DateTimeOffset local, DateTimeOffset world)
{
    var args = new Arguments { { typeof(IPassNow), passNow } };
    args.InsertTypedCollection(new object[] { local, world });
    return _container.Resolve<Event>(args);
}
  • registeredEarly 应该自动解决,它在组合根目录中注册,并且有效
  • passNowByInterface 应该在解析时传递,但因为它是一个接口,我需要指定接口类型,否则 Castle Windsor 将尝试使用参数的具体类型,同样有效 - 请参阅Failure to pass generic arguments with Castle Windsor
  • local 和 world 也需要在解析时传递,但请注意它们都是相同的具体类型,我不能依赖变量名 - 请参阅 Resolution-time arguments of same type in Castle Windsor
  • 我不能让最后一个与其他人一起工作?

【问题讨论】:

    标签: c# .net dependency-injection castle-windsor constructor-injection


    【解决方案1】:

    Resolve 方法有几个重载。 Arguments 类型只是 IDictionary,因此键不能相同。

    如果您尝试使用其构造函数创建Arguments 的实例,您将获得“System.ArgumentException”(已添加具有相同键的项。)

    var args = new Arguments(new object[] {passNow, local, world});
    

    如果您调试代码,您会发现字典中只有两个项目。

    var args = new Arguments {{typeof (IPassNow), passNow}};
    args.InsertTypedCollection(new object[] {local, world});
    

    为了使其工作,参数可以作为匿名类型传递。

    container.Resolve<Event>(new {passNow = passNow, local = local, world = world});
    

    有一个测试可以证明这一点

    [Fact]
    public void ArgumentsAsAnonimusType()
    {
        // Arrange.
        var container = new WindsorContainer();
        container.Register(Component.For<Event>().ImplementedBy<Event>());
        container.Register(Component.For<IRegisteredType>().ImplementedBy<RegisteredType>());
        var passNow = new PassNow();
        var local = DateTimeOffset.Now;
        var world = DateTimeOffset.UtcNow;
        local.Should().NotBe(world);
    
        // Act.
        var result = container.Resolve<Event>(new { passNow = passNow, local = local, world = world });
    
        // Assert.
        result.Should().BeOfType<Event>();
        result.RegisteredType.Should().Be(container.Resolve<IRegisteredType>());
        result.PassNow.Should().Be(passNow);
        result.Local.Should().Be(local);
        result.World.Should().Be(world);
    }
    

    【讨论】:

    • 不幸的是,这将不起作用,因为我正在传递具体类型 PassNow,而构造函数期望接口 IPassNow,因此需要明确指定,即查看此问题的答案stackoverflow.com/questions/14549577/…跨度>
    • 抱歉,您的示例确实有效,因为您正在指定文字变量名称,但我忘了提到我不能依赖文字变量名称,因为这不适用于混淆:( 所以我不能做 new {passNow = passNow 等,因为经过混淆后,构造函数参数将不再被称为 passNow..
    【解决方案2】:

    你们的工厂是什么样子的? 你试过 TypedFactoryFacility 吗?

    例如,在我的项目中,我有一个这样的构造函数:

    public SomeConcrete(ILog log, IDataBase dataBase, int param1, int param2, int param3, bool somebool)
    

    我的工厂是:

    public interface IFactory
    {
        SomeConcrete GetSomeConcrete(int param1, int param2, int param3, bool somebool);
    }
    

    并且通过变量名解析工作正常。

    如果你不习惯使用类型化工厂,你可以试试:

    container.Resolve<ISomeConcrete>(new {param1 = 1, param2 = 2, param3 = 3, somebool = false});
    

    更多信息在这里Typed Factory Facility

    也许this 也会有用。

    【讨论】:

    • 您的示例正在运行,因为您在解析时没有任何接口参数,即您没有等效的 IPassNow 或 GetSomeConcrete(ILog log, int param1, int param2 ..) - 再次,请看stackoverflow.com/questions/14549577/…
    • 我现在明白你的意思了。我为解决这个问题所做的就是在我的具体决议之前解决我的参考。假设我想在解析期间获取 ILog,所以它看起来像: ILog log = logFactory.GetLog();具体具体=concreteFactory.GetConcrete(log, param1, param2, param3, somebool);希望对你有帮助
    • 这行不通,试试吧,因为 SomeConcrete(ILog log ...) 在您传入 GetConcrete(log, ..) 时期待 ILog (温莎城堡将其视为 Log(而不是日志)
    • 如果您没有在其他任何地方注册 ILog,它应该可以工作。为我工作。抱歉,我帮不上忙。
    • 在这种情况下,我唯一能想到的就是创建名为 EventDate (或其他东西)的类,该类将包括 2 个属性,本地和世界,并将其传递给构造函数。这样你的构造函数将只有一个参数。
    【解决方案3】:

    我以为我找到了解决方案:

    public Event CreateEvent(IPassNow passNow, DateTimeOffset local, DateTimeOffset world)
    {
        var args = new Arguments(new { local, world });
        args.Insert(typeof(IPassNow), passNow);
        return _container.Resolve<Event>(args);
    }
    

    但这也不适用于混淆,结果是 new Arguments(new { local, world });也使用参数文字名称,而不是按顺序或其他东西匹配..所以这不是一个真正的答案..

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-13
      • 1970-01-01
      相关资源
      最近更新 更多