我正在构建一个Windows Forms应用程序,该应用程序使用静态MessageBox.Show()方法不时显示MessageBox。
我将静态调用包装在Repository对象中,如以下问题所示:How to use Dependency Injection with Static Methods?
在MainClass中,默认情况下,此Repository对象使用原始静态调用,但是MainClass还提供了用于设置此Repository对象的SetMessageBoxRepoDependency()方法。这为依赖项注入打开了选项。一种用法是使用模拟工具来引用Repository接口,并教导模拟的Show方法不要在测试期间创建真正的MessageBox。
但是,MainClass还会创建许多其他使用此Repository实例的对象。如何修改代码,以便在调用MainClass的SetMessageBoxRepoDependency()时,其他对象也将使用新的存储库?
(我可以修改MainClass的构造函数以使用自定义存储库,但想知道在MainClass创建之后如何设置存储库)
MainClass
public class MainClass
{
private IMessageBoxRepository messageBoxRepo;
public MainClass()
{
messageBoxRepo = new MessageBoxRepository();
// Just classes that reference the same Repository
var classA = new ClassA(messageBoxRepo);
var classB = new ClassB(messageBoxRepo);
var classC = new ClassC(messageBoxRepo);
}
public void SetMessageBoxRepoDependency(IMessageBoxRepository messageBoxRepo)
{
this.messageBoxRepo = messageBoxRepo;
}
}
MessageBoxRepository
public class MessageBoxRepository : IMessageBoxRepository
{
public DialogResult Show(string text)
{
return MessageBox.Show(text); // The original static call.
}
}
IMessageBoxRepository
public interface IMessageBoxRepository
{
DialogResult Show(string text);
}
答案 0 :(得分:0)
理想情况下,您希望您的DI容器可以进行 run 的操作:
namespace WindowsFormsApp1
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
var container = GetContainer();
// most likely the only resolve you need.
var form = container.Resolve<Form1>();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(form);
}
private static IContainer GetContainer()
{
// Register Dependencies
// Build the Container
// return Container;
}
}
}
假设您使用的是Autofac(我不了解其他框架,但是它们应该能够执行相同操作),则任何形式都应该能够将其构造函数签名更改为Func<>
以解决新问题。每次调用实例:
public class Form1
{
private Func<IMessageBoxRepository> _mbr;
public Form1(Func<IMessageBoxRepository> mbr)
{
_mbr = mbr;
}
public void OnError(string msg)
{
var mb = _mbr();
mb.Show(msg);
}
}
这意味着您不必到处都暴露容器(不必这样做,尤其是在计划进行单元测试时)。
然后,单元测试变得非常容易(示例假设使用NSubstitute,但是大家都做类似的事情):
public class Form1Test
{
public void OnError_WithAny_CallsShow()
{
// Arrange
var mbr = Substitute.For<IMessageBoxRepository>();
var mbrFunc = Substitute.For<Func<IMessageBoxRepository>>();
mbrFunc().Returns(mbr);
var form1 = new Form1(mbrFunc);
// Act
form1.OnError(null);
// Assert
mbr.Received().Show();
}
}