这是一个最低限度可重现的示例:
namespace IterableDisposeTest
{
interface IInstance
{
int ID { get; }
}
class Instance : IInstance
{
private static int p_counter = 0;
public int ID { get; }
public Instance(MagicVariable _magicVariable)
{
ID = p_counter++;
Console.WriteLine(_magicVariable.MagicString);
}
}
interface IProducer
{
public IEnumerable<IInstance> GetNextInstance();
}
class Producer : IProducer
{
private MagicVariable p_magicVariable;
public Producer(MagicVariable _magicVariable)
{
p_magicVariable = _magicVariable;
}
public IEnumerable<IInstance> GetNextInstance()
{
for (int i = 0; i < 42; i++)
yield return new Instance(p_magicVariable);
}
}
class ProducerFactory: IDisposable
{
private bool disposedValue;
private MagicVariable p_magicVariable = new MagicVariable();
public IEnumerable<Producer> GetNextProducer()
{
while (true)
yield return new Producer(p_magicVariable);
}
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
Console.WriteLine("ProducerFactory Disposed");
if (disposing)
{
}
p_magicVariable.Dispose();
disposedValue = true;
}
}
~ProducerFactory()
{
Dispose(disposing: false);
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
class MagicVariable: IDisposable
{
private string p_magicString = "I'm MAGIC!";
private bool p_disposedValue;
public string MagicString
{
get
{
ObjectDisposedException.ThrowIf(p_disposedValue, typeof(string));
return p_magicString;
}
}
protected virtual void Dispose(bool disposing)
{
if (!p_disposedValue)
{
Console.WriteLine("MagicVariable Disposed");
if (disposing)
{
}
p_disposedValue = true;
}
}
~MagicVariable()
{
Dispose(disposing: false);
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
static class SuperProducer
{
public static IEnumerable<IProducer> GetNextProducer()
{
using ProducerFactory factory = new ProducerFactory();
foreach(var producer in factory.GetNextProducer())
yield return producer;
}
}
internal class Program
{
static void Main(string[] args)
{
IProducer? producer = SuperProducer.GetNextProducer().FirstOrDefault((IProducer?)null);
if (producer != null)
{
// Thrown ObjectDisposedException there:
foreach (IInstance instance in producer.GetNextInstance())
Console.WriteLine($"Instance id is: {instance.ID}");
}
}
}
}
它会导致异常ObjectDisposedException,因为工厂在第 124 行退出语句时被释放。using困境如下 - 只有当语句中没有创建工厂时,错误才会消失using,但这与 RAII 概念相矛盾,工厂不会被创建。释放。如果你在 - 中创建一个工厂,那么它会在从第 126 行的循环using返回之前被释放。请告诉我这个示例中的架构错误是什么?IProducer你能怎样解决它?