C# 当一个构造函数明显更具体时,Autofac无法在两个构造函数之间解析

C# 当一个构造函数明显更具体时,Autofac无法在两个构造函数之间解析,c#,autofac,C#,Autofac,如果将委托注册为组件,则在解析时,AutowiringParam的优先级与NamedParameter的优先级相同 下面是一个简单的例子: public class AParam { } public class BParam : IParam { } public interface IParam { } public interface IAThing { } public class AThing : IAThing { public AThing(AParam aParam)

如果将委托注册为组件,则在解析时,AutowiringParam的优先级与NamedParameter的优先级相同

下面是一个简单的例子:

public class AParam { }
public class BParam : IParam { }

public interface IParam { }

public interface IAThing { }
public class AThing : IAThing
{
    public AThing(AParam aParam) { }
    public AThing(BParam anotherParam) { }
}

static void Main(string[] args)
{
    IContainer c = (new ContainerBuilder()).Build();

    var anotherBuilder = new ContainerBuilder();
    anotherBuilder.RegisterType<AThing>().As<IAThing>().InstancePerDependency();
    anotherBuilder.Register((context, parm) => new BParam()).As<BParam>().InstancePerDependency();
    anotherBuilder.Update(c);

    object aParam = new AParam();

    //Throws exception, it's unable to decide which constructor to use....
    var instance = c.Resolve(typeof(IAThing), new[] {new NamedParameter("aParam", aParam) });
}

我不确定在目前的情况下你真的能赢。对您来说“明显更具体”的内容不一定100%更具体-一旦您提供了参数,Autofac会将提供的参数与autowired参数一起获取,并在提供所有可用信息的情况下,尝试确定它可以实现哪些构造函数。所有参数都相等-无论它们来自注册时间(
builder.RegisterType().WithParameter(…)
),解析时间(
scope.resolve(…)
),还是自动连线-它应该调用哪个构造函数

如果有一个优先级,比如参数X比参数Y更重要,它实际上可能会变得非常复杂,并产生一些难以排除的行为。解析时间参数是否优先于注册时间参数?你能改变这种行为吗?为什么?事情变得一团糟

不管怎么说,这就是为什么它的行为是这样的,并且在未来可能会继续这样

但是,您有两个选择:

选项1-
使用构造函数
:您可以指定在测试中使用的构造函数是采用
BParam的构造函数(如果总是这样)

builder.RegisterType<AThing>()
  .As<IAThing>()
  .UsingConstructor(typeof(BParam));
这并不漂亮,但它完成了任务。如果您有很多这样的代码,您可以将其中的一部分封装到一个扩展方法中,该扩展方法生成默认注册ID,处理If/else逻辑,等等



我认为启用功能更强大的构造函数选择器是很有价值的,这样
UsingConstructor
就可以做更多的事情。为此,我想看看这是否是一个有趣的增强。

我注意到您的
Resolve
使用了
typeof(IAThing)
,但这不是您试图为其指定构造函数的具体类吗?还有,你有什么帮助吗?它还说,“如果声明了要创建实例的委托并使用了委托工厂,则可以实现更干净、类型安全的语法。”您可能可以通过委托和委托工厂来解决这一问题。嗨,Erik,一般来说,我们使用Autofac进行依赖项注入,因此它可能与我们试图解决的问题不完全相同(可能是一个测试模型),但肯定是带有命名参数“aParam”的构造函数。我不明白为什么Autofac会将“特殊性”(如果您愿意)指定给“aParam”构造函数,就像在旧版本的Autofac中使用的“AutowiringParameter”构造函数一样:/It’s,有点忽略我想要一个特定的参数名(键入的参数会导致相同的问题,顺便说一句)感谢您的回复正如详细解释的那样,应用程序组件具有多个构造函数是一种反模式。@史蒂文谢谢史蒂文,我将对此进行阅读。不过,一般来说,这只是一个微不足道的版本,它是一个庞大的代码库,支持多个应用程序,我正在修复它。我支持我的声明“用户指定参数”>autowiring param>default param。如果有一个构造函数具有两个autowiring参数,则可以忽略我的参数,我不会立即发现。我认为这显然具有更高的“特异性”因为我想显式地使用NamedParameter进行解析。如果没有,我不会对异常感到惊讶(或者在本例中,不会感到惊讶,因为唯一的构造函数是BParam)。Autofac已经尝试获取最具体的构造函数(长度更大),但在这种情况下,一个长度为2且带有两个自动连接参数的构造函数将以我在resolve调用中显式命名的1个参数战胜我的构造函数。我想的是CSS选择器中使用的某种特殊性规则,我不期望它能神奇地工作。但有一种想法认为这两种方式都有争议,但我解释的要点是anation解释了为什么会这样,而不是开始旁敲侧击。我希望我的回答能有所帮助。不幸的是,这个应用程序是一个野兽,它支持许多底层野兽,并进行了巨大的修改。旧版本的Autofac过去可以工作,有人更新了Autofac,我不得不咬紧牙关支持upda如果是这样的话,我自己就不会这么做了。我回复了你的票,非常感谢你的时间
builder.RegisterType<AThing>()
  .As<IAThing>()
  .UsingConstructor(typeof(BParam));
// This is the "default" behavior registration for when
// no parameters are provided. Note it's named, though, so
// the actual default registration for IAThing will be the
// lambda.
builder.RegisterType<AThing>().Named<IAThing>("default-thing");

// This is what will run when you Resolve<IAThing>()
builder.Register((ctx, p) => {
  var aorb = p
    .OfType<NamedParameter>()
    .Where(n => n.Name == "aParam")
    .FirstOrDefault();
  if (aorb != null)
  {
    // You passed the parameter so use it.
    return new AThing((BParam)aorb.Value);
  }
  else
  {
    // Use the default reflection-based registration, above.
    return ctx.ResolveNamed<IAThing>("default-thing", p);
  }
}).As<IAThing>();