结构图,使用默认实例和命名实例选项时的奇怪行为
有人能解释以下行为吗?
特别是为什么 TestInitializeAndConfigure_Fails 在 TestUseAndAdd 没有失败时失败...以及为什么 TestUse_Fails 在 TestUseOrderChanged 没有失败时失败。
感谢
代码
interface IResource {}
class TheFirstResource : IResource {}
class TheSecondResource : IResource {}
[TestFixture]
class Test
{
[Test]
public void TestUse_Fails()
{
ObjectFactory.Initialize(init =>
{
init.For<IResource>().Singleton().Use<TheFirstResource>();
init.For<IResource>().Singleton().Use<TheSecondResource>().Named("test");
});
IResource r1 = ObjectFactory.GetInstance<IResource>();
IResource r2 = ObjectFactory.GetNamedInstance<IResource>("test");
Console.WriteLine(string.Format("TestUse_Fails \n{0}\n{1}", r1, r2));
}
[Test]
public void TestUseOrderChanged()
{
ObjectFactory.Initialize(init =>
{
init.For<IResource>().Singleton().Use<TheSecondResource>().Named("test");
init.For<IResource>().Singleton().Use<TheFirstResource>();
});
IResource r1 = ObjectFactory.GetInstance<IResource>();
IResource r2 = ObjectFactory.GetNamedInstance<IResource>("test");
Console.WriteLine(string.Format("TestUseOrderChanged \n{0}\n{1}", r1, r2));
}
[Test]
public void TestUseAndAdd()
{
ObjectFactory.Initialize(init =>
{
init.For<IResource>().Singleton().Use<TheFirstResource>();
init.For<IResource>().Singleton().Add<TheSecondResource>().Named("test");
});
IResource r1 = ObjectFactory.GetInstance<IResource>();
IResource r2 = ObjectFactory.GetNamedInstance<IResource>("test");
Console.WriteLine(string.Format("TestUseAndAdd \n{0}\n{1}", r1, r2));
}
[Test]
public void TestInitializeAndConfigure_Fails()
{
ObjectFactory.Initialize(init =>
{
init.For<IResource>().Singleton().Use<TheFirstResource>();
});
ObjectFactory.Configure(init =>
{
init.For<IResource>().Singleton().Add<TheSecondResource>().Named("test");
});
IResource r1 = ObjectFactory.GetInstance<IResource>();
IResource r2 = ObjectFactory.GetNamedInstance<IResource>("test");
Console.WriteLine(string.Format("TestInitializeAndConfigure_Fails \n{0}\n{1}", r1, r2));
}
}
输出
TestUse_Fails
Smtesting.TheSecondResource
Smtesting.TheSecondResource
TestUseOrderChanged
Smtesting.TheFirstResource
Smtesting.TheSecondResource
TestInitializeAndConfigure_Fails
Smtesting.TheSecondResource
Smtesting.TheSecondResource
TestUseAndAdd
Smtesting.TheFirstResource
Smtesting.TheSecondResource
Is anybody able to explain the following behavior?
Especially why TestInitializeAndConfigure_Fails failes when TestUseAndAdd does not ... and why TestUse_Fails failes when TestUseOrderChanged does not.
Thanks
code
interface IResource {}
class TheFirstResource : IResource {}
class TheSecondResource : IResource {}
[TestFixture]
class Test
{
[Test]
public void TestUse_Fails()
{
ObjectFactory.Initialize(init =>
{
init.For<IResource>().Singleton().Use<TheFirstResource>();
init.For<IResource>().Singleton().Use<TheSecondResource>().Named("test");
});
IResource r1 = ObjectFactory.GetInstance<IResource>();
IResource r2 = ObjectFactory.GetNamedInstance<IResource>("test");
Console.WriteLine(string.Format("TestUse_Fails \n{0}\n{1}", r1, r2));
}
[Test]
public void TestUseOrderChanged()
{
ObjectFactory.Initialize(init =>
{
init.For<IResource>().Singleton().Use<TheSecondResource>().Named("test");
init.For<IResource>().Singleton().Use<TheFirstResource>();
});
IResource r1 = ObjectFactory.GetInstance<IResource>();
IResource r2 = ObjectFactory.GetNamedInstance<IResource>("test");
Console.WriteLine(string.Format("TestUseOrderChanged \n{0}\n{1}", r1, r2));
}
[Test]
public void TestUseAndAdd()
{
ObjectFactory.Initialize(init =>
{
init.For<IResource>().Singleton().Use<TheFirstResource>();
init.For<IResource>().Singleton().Add<TheSecondResource>().Named("test");
});
IResource r1 = ObjectFactory.GetInstance<IResource>();
IResource r2 = ObjectFactory.GetNamedInstance<IResource>("test");
Console.WriteLine(string.Format("TestUseAndAdd \n{0}\n{1}", r1, r2));
}
[Test]
public void TestInitializeAndConfigure_Fails()
{
ObjectFactory.Initialize(init =>
{
init.For<IResource>().Singleton().Use<TheFirstResource>();
});
ObjectFactory.Configure(init =>
{
init.For<IResource>().Singleton().Add<TheSecondResource>().Named("test");
});
IResource r1 = ObjectFactory.GetInstance<IResource>();
IResource r2 = ObjectFactory.GetNamedInstance<IResource>("test");
Console.WriteLine(string.Format("TestInitializeAndConfigure_Fails \n{0}\n{1}", r1, r2));
}
}
output
TestUse_Fails
Smtesting.TheSecondResource
Smtesting.TheSecondResource
TestUseOrderChanged
Smtesting.TheFirstResource
Smtesting.TheSecondResource
TestInitializeAndConfigure_Fails
Smtesting.TheSecondResource
Smtesting.TheSecondResource
TestUseAndAdd
Smtesting.TheFirstResource
Smtesting.TheSecondResource
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
为了帮助那些偶然发现这个问题的人,这里是杰米本人的回答。他在他的博客此处回答了这个问题。
For().Use() 具有破坏性。执行一次 For().Use() 以获得默认值,然后第二次调用 For().Add() 以获得第二次注册。查看这 2 个 API 调用的 Xml 注释。
Just to help the people who will stumble upon this, here is an answer from the man Jermey himself. He answered the question on his blog here.
For().Use() is destructive. Do For().Use() once to get the default, and a second call to For().Add() to get the 2nd registration. Look at the Xml comments for those 2 API calls.
TestUse_Fails 对我来说很有意义,因为调用 Use<>() 本质上意味着您正在指定类型的默认实例(并添加它)。最后一个通常会获胜——我找不到这方面的明确文档,但这是大多数容器的工作方式。 r1 调用获取 TheSecondResource(最后一个设置为默认值),r2 调用获取指定资源。
TestUseOrderChanged 之所以有效,是因为 init/config 后的默认值是 TheFirstResource,但 TheSecondResource 仍已添加到具有名称的容器中。因此,r1 获取 TheFirstResource(因为它是最后一个,因此是默认值),而 r2 正确获取 TheSecondResource 作为命名实例。
TestInitializeAndConfigure_Fails 是个奇怪的例子。从我的位置来看,r1 应该获得 TheFirstResource,因为默认值尚未被覆盖——Use<>() 尚未被再次调用。根据文档,在调用Initialize后调用Configure不应不重置容器。我会尝试调用 ObjectFactory.WhatDoIHave() 并查看 TheFirstResource 是否在 Initialize() 和 Configure() 调用后注册。
对我来说,这看起来像一个错误,我会考虑将其提交到结构图用户组(http://groups.google.com/group/structuralmap-users)。
TestUse_Fails makes sense to me, because calling Use<>() essentially means you are specifying the default instance for the type (and adding it). Last one in generally wins--I can't find explicit docs on this, but that's the way most containers work. The r1 call gets TheSecondResource (the last one set to be default), and the r2 call gets the named resource.
TestUseOrderChanged works because the default after init/config is the TheFirstResource, but TheSecondResource has still been added to the container with a name. So r1 gets TheFirstResource (as it was last in and thus the default), and r2 correctly gets TheSecondResource as the named instance.
TestInitializeAndConfigure_Fails is the odd one. From where I sit, r1 should get TheFirstResource, since the default has not been overwritten--Use<>() has not been called again. Calling Configure after calling Initialize should not reset the container according to the docs. I would try calling ObjectFactory.WhatDoIHave() and see if TheFirstResource is even registered after the Initialize() and Configure() calls.
To me, this looks like a bug, and I would consider submitting it to the structuremap users group (http://groups.google.com/group/structuremap-users).