【问题标题】:how to dispose off objects that implement IDiposable and also the types of properties/methods invoked on them implement IDisposable如何处理实现 IDiposable 的对象以及在它们上调用的属性/方法的类型实现 IDisposable
【发布时间】:2015-08-24 15:57:03
【问题描述】:

对我目前正在处理的 C# 对象类型有点困惑(也不确定)。

例如:

   interface IMyInterface
   {
       IDictionary<string, ICustomPath> MyPathDictionary { get; }
   }

由一个类实现,也实现了 IDisposable

   class MyClass:IMyInterface,IDisposable
   {
   }

   IMyInterface myInterface = new MyClass();

我知道如何处理对象 MyClass 的实例“myInterface”(通过 using 语句或显式将实例转换为 IDisposable 之类的

   ((IDisposable)myInterface).Dispose();
    or
    ((MyClass)myInterface).Dispose(); in the finally block after I'm done with what I'm doing.

但是我有类似下面的代码行

       IExampleInterface exampleInterface = some condition ? myInterface.MyPathDictionary[key]:myInterface.CreateSomething(key);

而 MyPathDictionary[key] 是一个字典值(其中键是字符串类型)和 IExampleInterface 类型的值,它由另一个名为 ExampleClass 的类实现,该类也实现 IDisposable 之类的。

   class ExampleClass:IExampleInterface,IDisposable
   {
   }

现在我的困惑是由上述条件语句引起的,因为使用专有工具分析我的代码表明 myInterface.MyPathDictionary[key] 导致资源/内存泄漏。我不确定的是,当我在 C# 代码的 finally 块中显式处理 myInterface 时,我是否也应该显式处理 myInteface.MyPathDiciotnary[key] 因为如果我已经处理了 myInterface 然后调用MyPathDictionary[key] 上的 (myInterface) 应该会自动处理掉。

任何关于这个难题的建议将不胜感激。

【问题讨论】:

  • 在这样的接口后面隐藏一个一次性类是很成问题的。该界面的用户不会知道他需要进行铸造体操来处理对象。而且永远不会。任何类型的静态代码分析器也很可能被彻底混淆,它无法将 Dispose() 调用连接到对象。您将不得不忽略该警告。通过从 IDisposable 继承您的接口,帮助客户端程序员陷入成功的陷阱。
  • 你对体操的事情是绝对正确的,但这是一个旧的遗留 C# 代码,我们在 COM 对象上创建包装器并在类上实现 IDisposable,而不是直接继承接口本身。我应该无论如何都要更改旧代码。
  • 对不起,这是我上面评论的最后一行的错字。我的意思是无论如何我都不应该更改遗留代码。

标签: c# .net


【解决方案1】:

如果MyClass 拥有这些资源,那么((IDisposable)myInterface).Dispose(); 应该处置它们。让一次性根对象递归调用它所拥有的任何东西的 dispose 是一种常见的模式。这会杀死整个对象树,这对调用者来说既方便又直观。

关键问题是 MyPathDictionary 中包含的对象是否拥有。

您的静态分析工具可能认为myInterface.MyPathDictionary[key] 是一个工厂方法,它创建它返回的内容。属性获取操作是方法调用。对于工具来说,这可能看起来像一个工厂。这是误报。

另一方面,如果您确实调用了myInterface.CreateSomething(key),那么这可能确实会产生一些必须处理的东西。您需要确保这一点。要么总是处理v,不管它的价值来自哪里。或者,通过区分这两种情况。

我只需将 v 包裹在 using 中即可。便于检查代码并得出正确的结论。

【讨论】:

  • 问题是,当我明确地处理掉 myInterface 时,我会自动处理掉 myInterface.MyPathDictionary[key] (如你所说),那么为什么我需要处理掉'v'。为什么不处理 myInterface 也会处理 myInterface.CreateSomething(key) 创建或返回的任何内容。这让我有点困惑。
  • 问题是'v'是IExampleInterface类型并且IExampleInterface不直接继承IDisposable,而是ExampleClass实现了IExampleInterface和IDisposable。那么我为什么可以直接在'v'上使用'using'语句。如果我需要使用“使用”语句,条件语句在语法方面会是什么样子。除了语法,我怎么能在作为接口的东西上使用 using 语句,而不是直接继承 IDisposable ,如本评论前面所述,
  • Disposal 是明确的,因为 CLR 不跟踪对象关系并传递地处理所有内容。您的代码必须对您想要处置的任何对象调用 Dispose。明白了吗?;您将无法在 v 上使用 using 语句,但您可以使用 using(v as IDisposable) 确保在 v 需要处理时它会得到它。
  • using(v as IDisposable) = 某些条件? myInterface.MyPathDictionary[key]:myInterface.CreateSomething(key);你觉得这没问题吗?
  • 这对我来说看起来像是无效的语法:) var v = ...; using (v as IDisposable) { rest. of code here }.
【解决方案2】:

如果您的接口的实现需要是一次性的,处理它的最佳方法是更改​​您的接口,以便它也实现 IDisposable。这样,界面的所有用户都清楚需要正确处理它。如果某些实现实际上不需要处理任何好的东西,它们只是有一个空实现。

【讨论】:

  • 这是一个遗留代码,无论如何我都不应该碰它。
  • @user2913184 太糟糕了,一个简单的解决方法是更改​​接口并添加一个提供实现的基类,并让所有现有类成为它的子类。
猜你喜欢
  • 2016-08-20
  • 2023-03-08
  • 2011-01-30
  • 1970-01-01
  • 2019-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-01
相关资源
最近更新 更多