简体   繁体   English

在实现IDisposable的类上正确使用Dispose方法

[英]Correct usage of Dispose method on class that implements IDisposable

I was working with some code today that used a System.Net.Mail.MailMessage class like so 我今天正在处理一些使用System.Net.Mail.MailMessage类的代码

public MailMessage CreateMessage(string fromAddress, string recipient)
{
    MailMessage message = new MailMessage(fromAddress, recipient);
    message.Subject = subject;
    message.Body = body;
    return message;
}

Ignoring the trivial nature of this method, I got a compiler warning saying 忽略了这种方法的微不足道的性质,我得到了编译器警告说

object 'message' is not disposed along all exception paths. 对象'消息'未沿所有异常路径放置。 Call System.IDisposable.Dispose on object 'message' before all references to it are out of scope. 在对所有引用超出范围之前,调用System.IDisposable.Dispose对象'message'。

This is interesting because the compiler is warning that the message is not disposed before it goes out of scope, but I would assume that returning a reference to it would mean that whilst the message variable is out of scope, the would still be a reference to the underlying object, in which case I doubt very much that I would want to dispose it. 这很有意思,因为编译器警告消息在超出范围之前没有处理,但是我会假设返回对它的引用意味着虽然消息变量超出范围,但仍然是基础对象,在这种情况下,我非常怀疑我会想要处理它。

This has left me a little confused as the implication of the warning message is that you shouldn't return disposable objects. 这让我有点困惑,因为警告信息的含义是你不应该返回一次性物品。 Is this really the case or is this just a case of compiler warning gone mad? 这是真的如此,还是这只是一个编译器警告疯狂的情况?

The meaning of this warning is that if the method throws (eg in the Subject setter), you could be left with an undisposed MailMessage which noone has any reference to. 此警告的含义是,如果方法抛出(例如,在Subject设置器中),您可能会留下一个没有任何引用的未公开的MailMessage

You are supposed to guard against this happening by something like this: 你应该通过这样的事情来防止这种情况发生:

public MailMessage CreateMessage(string fromAddress, string recipient)
{
    MailMessage message = new MailMessage(fromAddress, recipient);
    try {
        message.Subject = subject;
        message.Body = body;
        return message;
    }
    catch {
        if (message != null) {
            message.Dispose();
        }
        throw;
    }
}

The compiler doesn't have anything against returning IDisposable instances :) 编译器没有任何反对返回IDisposable实例的东西:)

One pattern I've seen which may sometimes be helpful is to create an object called a DisposeWrapper<T> which holds an IDisposable object of type T, supplied in the constructor, and which supports two methods: Keep and Dispose. 我见过的一个有时可能有用的模式是创建一个名为DisposeWrapper <T>的对象,它包含一个类型为T的IDisposable对象,在构造函数中提供,它支持两种方法:Keep和Dispose。 Calling Dispose without calling Keep will call Dispose on the wrapped IDisposable; 在不调用Keep的情况下调用Dispose将在包装的IDisposable上调用Dispose; calling Keep will prevent Dispose from hitting the IDisposable. 调用Keep将阻止Dispose击中IDisposable。

For convenience, it may be handy to have a static non-generic DisposeWrapper class with a generic factory method for DisposeWrapper<T> to allow the compiler to use method type inference to infer the type of the wrapper class. 为方便起见,使用静态非泛型DisposeWrapper类和DisposeWrapper <T>的通用工厂方法可能很方便,以允许编译器使用方法类型推断来推断包装类的类型。

One could thus do something like [I'm used to vb syntax, not c#, so apologies if this isn't quite right): 因此可以做一些像[我习惯于使用vb语法而不是c#的东西,所以如果这不是正确的话,请道歉):

{
  using(var wrapper = DisposeWrapper.Create(new SomeDisposableThing))
  {
    ... do some stuff with wrapper.Value;
    return wrapper.Keep();
  }
}

If the code reaches the "return wrapper.Keep();", then wrapper.Value will be returned and not disposed. 如果代码到达“return wrapper.Keep();”,则将返回wrapper.Value而不进行处理。 If the code exits the Using statement without calling wrapper.Keep, then wrapper.Value will be disposed. 如果代码在不调用wrapper.Keep的情况下退出Using语句,则将处理wrapper.Value。

It's sometimes annoying when compilers and tools insist that one must trap every possible way code could escape without cleaning up an IDisposable (especially when there's no way in C# to safely use field initializers with IDisposable fields) but I think wrapping an IDisposable should make the compiler happy. 当编译器和工具坚持认为必须捕获代码可以在不清除IDisposable的情况下逃脱的每种可能方式时(尤其是在C#中无法安全地使用具有IDisposable字段的字段初始化器时),但有时令人讨厌,但我认为包装IDisposable应该使编译器成为可能快乐。

An alternative pattern is to have a wrapper which holds a List of IDisposable, and use a generic method to "register" IDisposables as they are created (the method can return the new IDisposable as its appropriate type). 另一种模式是拥有一个包含IDisposable列表的包装器,并使用通用方法在创建IDisposable时“注册”它们(该方法可以将新的IDisposable作为其适当的类型返回)。 This can be a nice pattern to use in a constructor; 这可以是一个在构造函数中使用的好模式; with a little work it can also be used for field initializers in vb.net. 通过一些工作,它也可以用于vb.net中的字段初始化器。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 正确实现Finalize和Dispose的方法(当父类实现IDisposable时) - Correct way of implementing Finalize and Dispose(When parent class implements IDisposable) 检查方法是否使用反射实现IDisposable.Dispose - Check if method implements IDisposable.Dispose with reflection 没有Dispose函数实现IDisposable的类? - Class that implements IDisposable without Dispose function? Newtonsoft.Json.JsonWriter 实现 IDisposable 但没有 Dispose() 方法 - Newtonsoft.Json.JsonWriter implements IDisposable but has no Dispose() method C# IDisposable Class,正确使用 Dispose,出现错误“dispose”需要 1 个参数 - C# IDisposable Class, proper usage of Dispose, getting error 'dispose' takes 1 argument 当dispose()方法可以写在类中时,为什么要使用IDisposable - why use IDisposable when a dispose() method could be written in a class 如果没有Dispose方法,这个类如何实现IDisposable? - How does this class implement IDisposable if it doesn't have a Dispose method? 使用(IDisposable)vs. class字段-正确使用ReaderWriterLockSlim - using (IDisposable) vs. class field - correct usage of ReaderWriterLockSlim System.ServiceModel.ServiceHost实现IDisposable但Dispose不是公共的 - System.ServiceModel.ServiceHost implements IDisposable but Dispose is not public WebResponse在实现IDisposable时如何不公开显示“Dispose”? - How does WebResponse not have “Dispose” publically visible when it implements IDisposable?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM