对于C++(析构函数)中的等效机制,建议通常不应抛出任何异常.这主要是因为这样做可能会终止您的流程,这很少是一个好策略.
在.NET的等效场景中......
...您的流程不会立即终止.但是,由于.NET无法用第二个异常替换第一个异常,因此会丢失信息.因此,调用堆栈上某处的catch块将永远不会出现第一个异常.然而,人们通常对第一个例外更感兴趣,因为这通常会提供更好的线索,说明为什么事情开始出错.
由于.NET缺少一种机制来检测代码是否在异常处于挂起状态时被执行,因此似乎只有两种选择可以实现IDisposable:
那么,两个邪恶中哪一个较小?有没有更好的办法?
编辑:为了澄清,我不是在谈论积极抛出Dispose()或不抛出异常,我说的是让Dispose()调用的方法抛出的异常传播出Dispose()或不传播,例如:
using System;
using System.Net.Sockets;
public sealed class NntpClient : IDisposable
{
private TcpClient tcpClient;
public NntpClient(string hostname, int port)
{
this.tcpClient = new TcpClient(hostname, port);
}
public void Dispose()
{
// Should we implement like this or leave away the try-catch?
try
{
this.tcpClient.Close(); // Let's assume that this might throw
}
catch
{
}
}
}
Run Code Online (Sandbox Code Playgroud) 假设我有以下WCF实现:
public Stream Download(string path)
{
FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read);
return stream;
}
Run Code Online (Sandbox Code Playgroud)
谁负责处理退回的价值?毕竟,可能会发生网络故障,因此消费者可能无法处置它.
我有一个类来处理来自WinForms控件的事件.根据用户正在做的事情,我正在引用该类的一个实例并创建一个新实例来处理同一事件.我需要先从事件中取消订阅旧实例 - 这很容易.如果可能的话,我想以非专有方式这样做,看起来这是IDisposable的工作.但是,大多数文档仅在使用非托管资源时才建议使用IDisposable,这在此处不适用.
如果我实现IDisposable并取消订阅Dispose()中的事件,我是否会歪曲它的意图?我应该提供一个Unsubscribe()函数并调用它吗?
编辑:这是一些虚拟代码,它显示了我正在做的事情(使用IDisposable).我的实际实现与一些专有数据绑定(长篇故事)有关.
class EventListener : IDisposable
{
private TextBox m_textBox;
public EventListener(TextBox textBox)
{
m_textBox = textBox;
textBox.TextChanged += new EventHandler(textBox_TextChanged);
}
void textBox_TextChanged(object sender, EventArgs e)
{
// do something
}
public void Dispose()
{
m_textBox.TextChanged -= new EventHandler(textBox_TextChanged);
}
}
class MyClass
{
EventListener m_eventListener = null;
TextBox m_textBox = new TextBox();
void SetEventListener()
{
if (m_eventListener != null) m_eventListener.Dispose();
m_eventListener = new EventListener(m_textBox);
}
}
Run Code Online (Sandbox Code Playgroud)
在实际代码中,"EventListener"类涉及更多,每个实例都具有独特的重要性.我在集合中使用它们,并在用户点击时创建/销毁它们.
结论
我接受gbjbaanb的回答,至少目前如此.我觉得使用熟悉的界面的好处超过了在没有涉及非托管代码的情况下使用它的任何可能的缺点(这个对象的用户怎么会知道?).
如果有人不同意 - 请发帖/评论/编辑.如果可以对IDisposable做出更好的论证,那么我将改变接受的答案.
我已经编写了自己的自定义数据层来保存到特定文件,并使用自定义DataContext模式对其进行抽象.
这完全基于.NET 2.0 Framework(给定目标服务器的约束),所以尽管其中一些可能看起来像LINQ-to-SQL,但它不是!我刚刚实现了类似的数据模式.
请参阅下面的示例,以了解我无法解释的情况示例.
获取Animal的所有实例 - 我这样做,它工作正常
public static IEnumerable<Animal> GetAllAnimals() {
AnimalDataContext dataContext = new AnimalDataContext();
return dataContext.GetAllAnimals();
}
Run Code Online (Sandbox Code Playgroud)
并在下面的AnimalDataContext()中实现GetAllAnimals()方法
public IEnumerable<Animal> GetAllAnimals() {
foreach (var animalName in AnimalXmlReader.GetNames())
{
yield return GetAnimal(animalName);
}
}
Run Code Online (Sandbox Code Playgroud)
AnimalDataContext()实现了IDisposable,因为我在那里有一个XmlTextReader,我想确保它快速清理.
现在,如果我将第一个调用包装在using语句中,就像这样
public static IEnumerable<Animal> GetAllAnimals() {
using(AnimalDataContext dataContext = new AnimalDataContext()) {
return dataContext.GetAllAnimals();
}
}
Run Code Online (Sandbox Code Playgroud)
并在AnimalDataContext.GetAllAnimals()方法的第一行放置一个断点,在AnimalDataContext.Dispose()方法的第一行放置另一个断点,然后执行...
Dispose()方法被称为FIRST,因此AnimalXmlReader.GetNames()给出"对象引用未设置为对象的实例"异常,因为在Dispose()中AnimalXmlReader已设置为null ???
有任何想法吗?我有一种预感,它关系到产生收益没有被允许一个try-catch块,其内部被称为使用有效的代表,编译一次...
我的理解是,一旦代码退出块,.NET 中的using语句就会调用IDisposable对象的Dispose()方法.
using声明是否还做其他事情?如果没有,似乎以下两个代码示例实现完全相同的事情:
Using Con as New Connection()
Con.Open()
'do whatever '
End Using
Dim Con as New Connection()
Con.Open()
'do whatever '
Con.Dispose()
Run Code Online (Sandbox Code Playgroud)
我会给那些确认我是正确的人或者指出我错了并给出解释原因的人给出最好的答案.请记住,我知道某些类可以在其Dispose()方法中执行不同的操作.这个问题是关于using语句是否达到与调用对象Dispose()方法完全相同的结果.
在实现IDisposable时,我认为在对象被处理后不应该调用的每个方法都应该抛出ObjectDisposedException.但是应该传递给异常构造函数的name对象的标准是什么?
从以下情况开始:
public interface ISample
{
}
public class SampleA : ISample
{
// has some (unmanaged) resources that needs to be disposed
}
public class SampleB : ISample
{
// has no resources that needs to be disposed
}
Run Code Online (Sandbox Code Playgroud)
SampleA类应实现用于释放资源的接口IDisposable.您可以通过两种方式解决此问题:
1.将所需的接口添加到SampleA类:
public class SampleA : ISample, IDisposable
{
// has some (unmanaged) resources that needs to be disposed
}
Run Code Online (Sandbox Code Playgroud)
2.将其添加到接口ISample并强制派生类来实现它:
public interface ISample : IDisposable
{
}
Run Code Online (Sandbox Code Playgroud)
如果将其放入界面,则强制任何实现实现IDisposable,即使它们没有任何可处置的内容.另一方面,很清楚地看到接口的具体实现需要一个dispose/using块,而你不需要像IDisposable一样进行清理.在两种方式中可能会有更多的优点/缺点...为什么你建议使用一种优先于另一种方式?
如果我在C#中编写一个实现IDisposable的类,为什么我不能简单地实现
public void Dispose(){ ... }
Run Code Online (Sandbox Code Playgroud)
处理释放任何非托管资源?
是
protected virtual void Dispose(bool disposing){ ... }
Run Code Online (Sandbox Code Playgroud)
总是必要的,有时是必要的,还是其他的东西?
我终于在C#中围绕IoC和DI缠绕我的头,并且正在努力解决一些问题.我正在使用Unity容器,但我认为这个问题适用范围更广.
使用IoC容器来分配实现IDisposable的实例让我感到害怕!你怎么知道你应该Dispose()?该实例可能是专门为您创建的(因此您应该Dispose()它),或者它可能是其生命周期在其他地方管理的实例(因此您最好不要).代码中没有任何内容告诉您,实际上这可能会根据配置发生变化!这对我来说似乎是致命的.
任何IoC专家都可以描述处理这种模糊性的好方法吗?
IDisposable的实现是否可以安全地多次调用Dispose()?或者相反?大多数.NET Framework类采用什么方法?
具体来说,System.Data.Linq.DataContext.Dispose()多次通话是否安全?
我问的原因是因为我想知道是否需要这种额外保护:
public override void Dispose(bool disposing)
{
// Extra protection...
if (this.obj != null)
{
this.obj.Dispose();
this.obj = null;
}
// Versus simply...
this.obj.Dispose();
base.Dispose(disposing);
}
Run Code Online (Sandbox Code Playgroud)
在处理类的IDisposable成员时,或者我是否应该在this.obj.Dispose()不关心之前调用它的情况下调用它.
idisposable ×10
.net ×8
c# ×7
dispose ×2
using ×2
.net-2.0 ×1
events ×1
stream ×1
unsubscribe ×1
vb.net ×1
wcf ×1
yield-return ×1