如何解决WPF单元测试中无法加载DispatcherTimer类型的异常
解决.NET 7测试项目加载WindowsBase中DispatcherTimer类型失败的问题
原因分析
你的测试项目目标框架是.NET 7(属于.NET Core生态),而被测试的WPF项目基于.NET Framework 4.7.2,两者的WindowsBase.dll分属不同技术生态,版本与底层实现存在差异,导致运行时无法匹配到正确的类型。
解决办法
方案一:将测试项目切换为.NET Framework 4.7.2
这是最直接的解决方案,确保测试与被测试项目框架完全一致:
- 右键测试项目 → 属性 → 应用 → 目标框架,选择
.NET Framework 4.7.2 - 重新引用WPF项目,编译调试即可彻底避免程序集版本冲突
方案二:在.NET 7测试项目中引入WPF依赖并配置绑定重定向
如果必须保留.NET 7测试项目,需让项目正确识别WPF相关程序集:
- 修改测试项目的
.csproj文件,添加WPF支持:
<PropertyGroup> <TargetFramework>net7.0-windows</TargetFramework> <UseWPF>true</UseWPF> </PropertyGroup>
- 新建或修改
app.config文件,添加程序集绑定重定向,引导运行时加载正确版本的WindowsBase:
<configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="WindowsBase" publicKeyToken="31bf3856ad364e35" culture="neutral" /> <bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="7.0.0.0" /> </dependentAssembly> </assemblyBinding> </runtime> </configuration>
方案三:抽象定时器依赖,实现无耦合测试
通过接口解耦Battery类与DispatcherTimer的直接依赖,从根源消除跨框架程序集问题:
- 定义定时器接口:
public interface ITimer { event EventHandler Tick; TimeSpan Interval { get; set; } void Start(); void Stop(); }
- 在WPF项目中实现基于
DispatcherTimer的适配器:
public class DispatcherTimerAdapter : ITimer { private readonly DispatcherTimer _timer; public event EventHandler Tick; public TimeSpan Interval { get => _timer.Interval; set => _timer.Interval = value; } public DispatcherTimerAdapter() { _timer = new DispatcherTimer(); _timer.Tick += (s, e) => Tick?.Invoke(s, e); } public void Start() => _timer.Start(); public void Stop() => _timer.Stop(); }
- 修改
Battery类,通过构造函数注入ITimer:
public class Battery { private readonly ITimer _timer; public Battery(ITimer timer) { _timer = timer; _timer.Interval = TimeSpan.FromSeconds(1); _timer.Tick += OnTimerTick; } private void OnTimerTick(object sender, EventArgs e) { // 原有定时器逻辑 } }
- 测试项目中使用模拟定时器,手动控制事件触发:
public class MockTimer : ITimer { public event EventHandler Tick; public TimeSpan Interval { get; set; } public void Start() { } public void Stop() { } // 测试时手动触发Tick事件 public void RaiseTick() => Tick?.Invoke(this, EventArgs.Empty); }
这种方式不仅解决了跨框架问题,还让测试逻辑更灵活,无需依赖WPF运行环境。
内容的提问来源于stack exchange,提问作者Ming
相关产品推荐
相关产品推荐

