如何解决Ninject 在处理使用它的父对象之前处理子对象
当我在 DataTest 的 IKernel.Dispose()
方法中调用 [TestCleanup]
时,我的应用程序崩溃了,因为要释放的第一个对象仍在被另一个对象使用。
此代码重现了该问题:
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Ninject;
using Ninject.Modules;
[TestClass]
public class NinjectDisposeIssue
{
private IKernel kernel;
[TestInitialize]
public void TestInitialize()
{
kernel = new StandardKernel(new Module());
}
[TestCleanup]
public void TestCleanup()
{
kernel.Dispose();
}
[DataTestMethod]
[DataRow]
[DataRow]
public void DataTestMethod()
{
var parent = kernel.Get<Parent>();
parent.Run();
}
}
public class Module : NinjectModule
{
public override void Load()
{
Bind<Parent>().ToSelf().InSingletonScope();
Bind<Service>().ToSelf().InSingletonScope();
Bind<Database>().ToSelf().InSingletonScope();
// create 2 workers
Bind<Worker>().ToSelf().InSingletonScope();
Bind<Worker>().ToSelf().InSingletonScope();
}
}
public class Parent
{
private readonly Service service;
private readonly IEnumerable<Worker> workers;
public Parent(Service service,IEnumerable<Worker> workers)
{
this.service = service;
this.workers = workers;
}
public void Run()
{
for (var i = 0; i < 2; i++)
{
foreach (var worker in workers)
{
worker.StartWork();
}
service.DoSomething();
}
}
}
public class Service
{
private readonly Database database;
public Service(Database database)
{
this.database = database;
}
public void DoSomething()
{
var value = database.Get();
// do something with the value
}
}
public class Worker : IDisposable
{
private readonly Database database;
private Task workTask;
private CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
private bool disposedValue;
public Worker(Database database)
{
this.database = database;
}
public void StartWork()
{
if (workTask == null)
{
workTask = Task.Run(WorkLoop);
}
}
private void WorkLoop()
{
while (!cancellationTokenSource.Token.IsCancellationRequested)
{
var value = database.Get();
// do some work with the value...
}
}
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
cancellationTokenSource.Cancel();
workTask.Wait();
workTask.Dispose();
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
public class Database : IDisposable
{
private readonly ThirdPartyDb thirdPartyDb = new ThirdPartyDb();
private bool disposedValue;
public string Get()
{
return thirdPartyDb.Get("foo");
}
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
thirdPartyDb.Dispose();
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
public class ThirdPartyDb : IDisposable
{
private bool isDisposed = false;
public void Dispose()
{
isDisposed = true;
}
public string Get(string key)
{
if (isDisposed)
{
throw new ObjectDisposedException(nameof(ThirdPartyDb));
}
return "bar";
}
}
Dispose()
对象的 Database
方法在 2 个 Dispose()
的 Worker
方法之前被调用。
问题:我可以在绑定中做些什么来强制在 Worker
之前处理 Database
还是我的配置方式根本错误?
解决方法
作为一个简单的解决方案,您只需将另一个 select replace(translate(upper(class_0),' (),','_'),'Band','BD') class_4
from (
select 'Higher Education Worker Level 10,Band 2 (salaried)' class_0
)
添加到您的 CancellationTokenSource
。这样您就可以确保 Database
在处理后不会被调用。
thirdPartyDb
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。