【问题标题】:What's the difference between these two StructureMap configs?这两个 StructureMap 配置有什么区别?
【发布时间】:2011-12-10 02:01:02
【问题描述】:

我们正在努力理解这两种配置 StructureMap 的方式之间的区别。我们的理解是它们应该是相同的,但是我们在 Initialize 中的这两行之间得到了不同的结果:

ObjectFactory.Initialize(x =>
{
    x.For<IBusinessRelationsContext>().Use<BusinessRelationsContext>().Ctor<string>().Is(ConfigurationManager.ConnectionStrings["BusinessRelationsContext"].ConnectionString);
    x.For<IBusinessRelationsContext>().Use(_ => new BusinessRelationsContext(ConfigurationManager.ConnectionStrings["BusinessRelationsContext"].ConnectionString));
});

(我们一次只使用两个中的一个 - 显然不是两个)

我们在这个对象上的各种构造函数签名(如果你关心的话,它是 EF4 的东西):

public BusinessRelationsContext();
public BusinessRelationsContext(string connectionString);
public BusinessRelationsContext(EntityConnection connection);

我们用来调用它的代码是:

ObjectFactory.TryGetInstance<IBusinessRelationsContext>();

我们看到的行为差异是包含 Ctor&lt;string&gt; 的行失败,因为 StructureMap 失败并显示 202“No Default Instance defined for PluginFamily System.Data.Common.DbConnection”(我们不知道它为什么会这样认为需要这个)。但是,如果我注释掉该行并使用另一行,它会像我们预期的那样完美运行。鉴于另一个有效,我怀疑我对 DbConnection 不需要配置的理解是正确的。

因此,与其追查为什么它需要 DbConnection,我宁愿追查我的问题的答案:这两者之间有什么区别?

【问题讨论】:

  • 这有点重要,因为我们过去一直使用.Ctor 的方式来执行此操作(并且一直有效),但考虑到它开始失败(我们不确定为什么),我们需要更好地理解这一点。我们在这里在概念上遗漏了一些东西,我不想有一个定时炸弹......
  • 我想我自己也亲眼见过这种情况,使用 Ctor 似乎不起作用。
  • 我理解 Ctor 的做法是否正确,基本上我说:“对于 IBusinessRelationsContext 实例,使用 BusinessRelationsContext 对象并调用Constructorsingle string 参数并传入 ConfigurationManager.ConnectionStrings["BusinessRelationsContext"].ConnectionString 评估为该字符串参数”?还有什么别的吗?
  • 有趣的是,我们使用Ctor 方式与其他上下文对象一起使用!因为我们的数据库太大了,我们有大约 20 个不同的上下文,因为我们把它分成几个部分,它适用于所有 20 个部分。碰巧的是,在这些特定的单元测试中,这个特定的上下文失败了,而其他上下文使用 Ctor 方法可以正常工作。 (所有上下文都是从同一个模板生成的代码,所以没有区别!)
  • 这绝对是我对它的理解,我已经使用 SM 3 年多了。上次我想做这样的事情时,我很确定我最终不得不做类似于你在 Use 中手动更新对象所做的事情。

标签: c# .net-4.0 dependency-injection structuremap


【解决方案1】:

我认为 StructureMap 正在选择最复杂的构造函数来尝试创建您的数据上下文。您使用 Ctor 调用在那里定义的是关于如何使用不太复杂的构造函数定义该类的定义。

所以你的定义没有错,只是 StructureMap 没有调用你认为它应该调用的构造函数。

注意:我通常使用您的第二个调用,因为我知道将调用哪个构造函数,即使您必须添加新的构造函数以进行测试或其他目的。

x.For<IBusinessRelationsContext>().Use(_ => new BusinessRelationsContext(ConfigurationManager.ConnectionStrings["BusinessRelationsContext"].ConnectionString));

【讨论】:

  • 就是这样,但不止于此。我即将发布使 .Ctor 工作的解决方案! :-D
  • 授予您该问题的答案,但我在另一个答案中发布了该问题的解决方案。 :)
  • 太棒了,你想通了。如果你的功劳是正确的,你不必给我功劳。我希望人们看到正确的答案。即使这意味着我的信誉较低。
  • 嗯,你的答案是问题的正确答案。问题是,“有什么区别?”我之前没有考虑过的正确答案是“StructureMap 没有调用我认为它应该调用的构造函数”。我发布的答案是对明显后续问题的回答:“我如何让它调用我认为它应该调用的构造函数?” :)
【解决方案2】:

所以我让某人离线帮助我解决这个问题(没想到我会有任何离线资源!)问题正如 Khalid Abuhakmeh 解释的那样 - 它正在选择最复杂的一个(“最贪婪” - @ 987654321@).

现在我们知道了问题所在,我们可以寻找解决方案。就我而言(以及此处评论的情况),解决方案是添加如下一行:

x.SelectConstructor<IBusinessRelationsContext>(() => new BusinessRelationsContext(""));

【讨论】:

  • 恕我直言,即使我的配置行以强类型和唯一标识的方式明确指定构造函数的参数,StructureMap 任意选择构造函数也是绝对可怕的。那很糟! (来自以前从未开发过 DI 引擎的人)
  • 这不是任意的。 StructureMap 总是选择最贪婪的构造函数。这是有据可查的行为。您的配置行(在问题中)指定了一个构造函数参数的值 - 它没有指定构造函数。可以指定字符串构造函数参数,同时让容器自动解析任何其他参数。
  • @Joshua:在这种情况下,我有两个同样贪婪的构造函数。两个构造函数接受一个参数。其中一个恰好接收单个字符串(我指定了一个字符串类型),而另一个接收单个 EntityConnection。我们已经成功使用 .Ctor 方法一年半了,但是有了这个问题,我们第一次遇到了 StructureMap 会选择另一个构造函数的问题。这两个构造函数都已经使用了 1.5 年,并且签名没有改变。如果您认为这不是任意的,请解释一下突然的行为变化。
  • 选择最贪婪的人并不是任意的——看来这就是你反对的。如果你有一个最贪婪的领带,那么是的,它会有点武断,因为它依赖于构造函数从 .NET 反射返回的顺序。它总是选择第一个。如果 .NET 运行时发生更改,或者其算法以不同的顺序返回它们(这当然是可能的 - 反射 API 不保证顺序),您将选择不同的构造函数。要么你升级了你的 FX,要么你总是靠运气得到预期的 ctor,直到现在。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-19
  • 2012-06-12
  • 2016-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多