如何使用自定义生成器来处理IDisposable类型?

3
请注意:这是关于fscheck的问题,而不是关于C#中IDisposable的一般使用方法。
假设我有以下类(为了说明问题进行了夸张):
public class MyDataTypeWrapper : IDisposable
{
    private MyDataType fMyDataType; // MyDataType implements IDisposable

    public MyDataTypeWrapper(int[] randomData)
    {
         // some conversion routine (not shown)
         var inputToMyDataType = ConvertRandomDataToMyDataInputs(randomData);

         // this could all be done in one method but breaking out into two to illustrate.
         fMyDataType = new MyDataType(inputToMyDataType);
    }

    public void Dispose()
    {
         fMyDataType.Dispose();
    }
}

MyDataType消耗了一些非托管资源,因此它实现了IDisposable接口。 MyDataType类实际上没有一个接受int[]的构造函数,因此使用了包装类。

创建这个的生成器相对简单,但我无法看到任何方法让这样的生成器在每次测试迭代后也负责处理已创建的对象的释放,这意味着我的测试代码经常充斥着显式调用Dispose的语句。请参见下面的概述示例。

var generator = from randomData in Arb.Generate<int[]>()
                select new MyDataTypeWrapper(randomData);

// use the generator as input to some fscheck property based tests
Prop.ForAll(generator.ToArbitrary(), (MyDataTypeWrapper randomClassUnderTest) =>
{
    // want to avoid this
    using(randomClassUnderTest)
    {
        // assert some properties
        ...
    }
}).QuickCheckThrowOnFailure();

Prop.ForAll(generator.ToArbitrary(), (MyDataTypeWrapper randomClassUnderTest) =>
{
    // assert some properties
    ...

    // also want to avoid this (equivilant to use of using in example above)
    randomClassUnderTest.Dispose();
}).QuickCheckThrowOnFailure();

任何关于如何避免此问题的想法和建议都将不胜感激。

using 块? - Ehsan Sajjad
好的 - 它会放在哪里?它与显式调用Dispose并没有真正的区别(即它位于测试委托内部)。 - cristobalito
编写一个 Prop.ForAllDisposable,它会显式地处理传递给它的每个元素。这在一般情况下显然是不安全的,因此扩展/遮蔽 Prop.ForAll 以处理所有可处理对象是可能的,但不建议这样做。您还可以编写一个 IEnumerable 包装器,在每次调用 Enumerator.MoveNext 时处理其包装的枚举的前一个元素,这更为通用(同样也不应随意执行)。 - Jeroen Mostert
1
@mm8 我不同意这个观点 - 你可以在多个消费者之间共享任何IDisposable的实例,因此你肯定不想让第一个完成对象操作的消费者对其进行处理。 - cristobalito
@Lee - 这很有趣,但归根结底还是要使用 using 语句或直接调用 Dispose。如果可能的话,我希望在 fscheck 框架中找到一个解决方案。 - cristobalito
显示剩余12条评论
1个回答

1

第一个解决方案非常明显,但我还是会提及它,因为它实际上回答了问题:

var generator = from randomData in Arb.Generate<int[]>()
                select new MyDataTypeWrapper(randomData);

Prop.ForAll(generator.ToArbitrary(), (MyDataTypeWrapper randomClassUnderTest) =>
{

   using(randomClassUnderTest)
   {

   }

}).QuickCheckThrowOnFailure();

如果您不想为每个元素都这样做,您需要创建一些辅助方法来为您完成,例如:
  public static WhateverItReturns DisposablePropAll<TDisposable>(this IEnumerable<TDisposable> elements, Action<TDisposable> action) where TDisposable : IDisposable
        {
            return Prop.ForAll(elements, (TDisposable randomClassUnderTest) =>
            {
                using (randomClassUnderTest)
                {
                    action(randomClassUnderTest);
                }
            });
        }

感谢您抽出时间,但是您所建议的与我的示例代码在功能上是等效的。这个问题实际上是关于是否有一些本地支持在fscheck中创建IDisposable对象的生成器。 - cristobalito

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接