我应该将 C# 的 using 语句与哪些类一起使用?

发布于 2024-09-08 05:17:08 字数 571 浏览 4 评论 0原文

我已阅读并相信我理解 C# 的 using 语句的作用(如果我错了,请纠正我):将 IDisposable 对象初始化为只读,范围有限(using< /代码> 块)。我知道您可以在 using 之前进行初始化,这不会限制范围,但建议不要这样做:

http://msdn.microsoft.com/en-us/library/yh598w02.aspx

我并不总是关注哪些类是哪些类的子类。我不太确定哪些类继承自 IDisposable。我不仅好奇在 using 语句中可以使用哪些类,而且我的同事希望在 using 块中找到哪些类? 应该哪些类位于 using 块中?另外,不使用 using 块并且不调用 Dispose 真的有什么问题吗?仅仅与内存有关还是与稳定性有关?

I've read and I believe I understand what C#'s using statement does (please correct me if I'm wrong): Initializes an IDisposable object as read only to a limited scope (the using block). I know you can initialize before the using and that doesn't limit the scope, but that is advised against here:

http://msdn.microsoft.com/en-us/library/yh598w02.aspx

I'm not always paying attention to what classes are subclasses of what. I'm not too sure what classes inherit from IDisposable. I'm not just curious what classes can be used in a using statement, but what classes would my coworkers expect to find in a using block? What classes should be in a using block? Also, is there really anything wrong with not using a using block and not calling Dispose? Is it just about memory or also stability?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

嗳卜坏 2024-09-15 05:17:08

严格来说,任何实现了 IDisposable 且其范围仅限于该函数的对象都应该位于 using 块内。 IDisposable 接口的存在是为了允许处理非托管资源(数据库连接、文件句柄、窗口句柄等)的类及时、确定地处理这些资源。

一般来说,在类中使用 IDisposable 对象有以下三种方式:

  1. 在单个方法调用的范围内创建该对象,并且不再需要该对象。这是很常见的,并且是在可以(并且应该)使用 using 的情况下。
  2. 对象由类创建(或传递给类),其生命周期超出单个方法调用的范围,但不超出类的生命周期。例如,您的类创建一个 Stream 并需要在对象的生命周期内使用它。在这种情况下,您的类应该实现 IDisposable 本身,并在调用您自己的 Dispose 方法时处置您拥有的对象。例如,System.IO.StreamWriter
  3. 对象被传递给类,但类并不“拥有”它。这意味着 IDisposable 对象的可用生命周期超出了单个方法调用的范围,并且可能超出了对象的生命周期。在这种情况下,必须由其他人负责调用 Dispose

第一种情况是您最常遇到的情况,这就是 using 块存在的原因。它负责确保即使在发生异常的情况下也会处理该对象。

一些示例:

  • 流类
  • 数据库连接/命令
  • 控件

没有实现 IDisposable 的类的详尽列表,因为该列表相当大,并且充满了您可能永远不会遇到的类。想想这个类做什么;它是否打开某种需要关闭的连接或文件?一般来说,它是否获取某种需要释放的资源?如果是这样,它可能会实现它。在基本层面上,如果编译器允许您将其包含在 using 中,那么它就实现了 IDisposable

至于调用Dispose的后果,不用考虑。 调用 Dispose。确实,防御标准是,如果您的类直接使用非托管资源,那么您应该定义一个终结器,该终结器将在您的对象被收集并且有人未能调用它时调用 dispose,但是不应该是一个设计选择。据我所知,曾经如此。

Strictly speaking, any object that implements IDisposable and whose scope is limited to that function should be within a using block. The IDisposable interface exists to allow classes that deal with unmanaged resources (database connections, file handles, window handles, etc.) to dispose of these resources in a timely, deterministic fashion.

There are, in general, three ways in which an IDisposable object is used within a class:

  1. The object is both created and no longer needed within the scope of a single method call. This is quite common, and is when using can (and should) be used.
  2. The object is created by the class (or is passed to the class), and its lifetime extends beyond the scope of a single method call but not beyond the life of the class. For example, your class creates a Stream and needs to use it over the lifetime of the object. In this case, your class should implement IDisposable itself and dispose of the object(s) that you own when your own Dispose method is called. An example of this would be something like System.IO.StreamWriter
  3. The object is passed to the class, but the class doesn't "own" it. This means that the IDisposable object's usable lifetime is beyond the scope of a single method call, and may be beyond the lifetime of your object. In this case, someone else must be responsible for calling Dispose.

The first case is the most common that you'll encounter, which is why the using block exists. It takes care of ensuring that the object will be disposed of, even in the case of an exception.

Some examples:

  • Stream classes
  • Database connections/commands
  • Controls

There's no exhaustive list of classes that implement IDisposable, as that list would be fairly large and filled with classes that you'll likely never encounter. Think about what the class does; does it open some sort of connection or file that needs to be closed? In general, does it acquire some kind of resource that needs to be released? If so, it probably implements it. At a basic level, if the compiler allows you to enclose it in using, then it implements IDisposable.

As to the consequences of not calling Dispose, don't consider it. Call Dispose. True, the defensive standard is that if your class uses unmanaged resources directly, then you should define a finalizer that will call dispose in the event that your object is collected and someone has failed to call it, but that should not be a design choice. Ever, as far as I'm aware.

千纸鹤 2024-09-15 05:17:08

这与记忆无关。它与其他资源有关,例如文件句柄、数据库连接等。

基本上,如果一个类实现了 IDisposable,那么这是一个信号,表明您应该在完成后处理它,因为它可能具有非托管资源,这会导致留在周围会很昂贵。 (例如,您的连接池可能会耗尽连接,或者文件句柄将保持打开状态,从而阻止另一段代码再次打开同一文件)。

It's not about memory. It's about other resources such as file handles, database connections etc.

Basically if a class implements IDisposable, that's a signal that you should dispose of it when you're done, because it may have unmanaged resources which would be expensive to leave around. (e.g. your connection pool may run out of connections, or a file handle will stay open, preventing another piece of code from opening the same file again).

喵星人汪星人 2024-09-15 05:17:08

您应该始终在任何实现IDisposable的类上调用Dispose,这可以通过using块轻松完成。

这不仅仅是记忆的问题。这也不仅仅是资源的问题。这是关于正确性的。

StreamWriter 是一个著名的例子。微软甚至开发了MDA来捕获程序员忘记的一些情况调用Dispose。这不仅仅是内存或资源:在 StreamWriter 示例中,正在写入的文件可能会被截断。

有一次,我不得不追踪一个令人讨厌的错误(实际上是在我老板的代码中),其中数据库事务被回滚......事实证明,原因是 Dispose 没有被调用,因此当进程退出时它试图向磁盘提交太多内容(进程退出期间终结器超时)。修复只是几个 using 块。

第三个示例:Microsoft 的托管 ESENT 包装类具有“三层”处置方案,要求 以正确的顺序调用 Dispose(最后是“外部”类)。

因此,在三个现实世界的示例中,如果未正确调用 Dispose,将会导致不正确的行为。其他类可能会表现出类似的行为。

作为一般规则,您应该始终调用Dispose

You should always call Dispose on any class that implements IDisposable, and this is most easily done via a using block.

This is not just about memory. This is also not just about resources. This is about correctness.

StreamWriter is a famous example. Microsoft has even developed an MDA to catch some cases where programmers forgot to call Dispose. This is more than just memory or resources: in the StreamWriter example, a file being written may be truncated.

I had to track down a nasty bug one time (in my boss' code, actually), where a database transaction was being rolled back... turns out the cause was that Dispose wasn't being called, so it was trying to commit too much to disk when the process exited (there's a timeout for finalizers during process exit). The fix was just a few using blocks.

A third example: Microsoft's Managed ESENT wrapper classes have a "three tier" disposal scheme that requires Dispose to be called in the correct order ("outer" classes last).

So, there are three real-world examples where incorrect behavior will result if Dispose is not called properly. Other classes may exibit similar behavior.

As a general rule, you should always call Dispose.

初见终念 2024-09-15 05:17:08

至少,所有使用非托管资源的类

At least, all class that used non managed resources

我的痛♀有谁懂 2024-09-15 05:17:08

不使用 using 块并且不调用 Dispose 绝对是有很多错误的,您很可能会泄漏内存和/或资源。使用很方便,但您确实应该在从 IDisposable 派生的类的任何对象中调用 Dispose。

There is absolutely a lot wrong with not using a using block and not calling Dispose, you most likely will leak memory and / or resources. Using is a convenience, but you really should call Dispose in any object which class derives from IDisposable.

榆西 2024-09-15 05:17:08

至于哪些类是一次性的,您可以自己探索智能感知,或者您只是从经验中学习。一些常见的包括 Image 及其子级,实际上大部分 System.Drawing 命名空间、大量文件流、数据库连接等。

至于何时应该调用它- 尽快地。如果您知道它是一次性的,并且知道您已经用完它,那么请调用 Dispose。

我相信许多实现 IDisposable 的 .NET 基类都实现了一次性模式,这意味着当垃圾收集器来获取它们时,它们将被正确地处理。但即便如此,您仍然应该在完成后处理掉一些东西,因为

  1. 您可能会留下一个引用(泄漏)并且它不会被处理,或者
  2. GC 可能会暂时不会出现。

此外,对于您自己编写的类,垃圾收集并不等于对非托管资源的正确处置 - 这是一个常见的混淆。一次性模式需要自己实现。

As far as what classes are disposable, you can probe intellisense yourself, or you'll just learn from experience. Some common ones include Image and its children, in fact most of System.Drawing namespace, plenty of file streams, database connections, etc.

As far as when it should be called - as soon as possible. If you know it's disposable, and you know you're done with it, then call Dispose.

I believe many of the .NET base classes that implement IDisposable implement the disposable pattern, which means that they will be disposed of, properly, when the garbage collector comes to get them. But even so, you should still dispose of things when you're done, because

  1. You may leave a reference hanging around (a leak) and it won't be disposed, or
  2. The GC may not come around for a while.

Additionally, for classes you write yourself, garbage collection does NOT equate to proper disposal for unmanaged resources - a common confusion. The disposable pattern needs to be implemented yourself.

臻嫒无言 2024-09-15 05:17:08

类实现 IDisposable 的主要原因是释放非托管资源。当托管资源超出范围并且它认为合适时,垃圾收集器将释放它们,但它不了解非托管资源。调用Dispose方法将显式释放资源。

如果您不使用 using 块或调用 Dispose 方法,那么您将遇到内存泄漏问题,进而可能导致稳定性问题。

在处理实现 IDisposable 的类时,您应该始终使用 using 块。尽管您可能更喜欢 Try.. Catch.. Final 确保在 finally 块中调用 Dispose,以便可以处理异常。

The main reason a class would implement IDisposable is to release non managed resources. The garbage collector will release managed resources as they go out of scope and it sees fit, but it has no knowledge of non managed resources. Calling the Dispose method will explicitly release the resources.

If you do not use a using block or call the Dispose method then you will have a problem with memory leakage, which in turn could cause stability issues.

You should use a using block at all times when dealing with classes that implement IDisposable. Although you may prefer a Try.. Catch.. Finally ensuring that you call Dispose in the finally block so you can deal with exceptions.

撩动你心 2024-09-15 05:17:08

IDisposable 的目的是使与非托管资源(如文件、数据库或图形上下文)交互的对象能够自行清理。 using 语句是以下构造的便捷简写。

var disposable = new MemoryStream();
try
{
  //do some work with the disposable object
}
finally
{
  if (disposable!=null)
     disposable.Dispose();  
}

当然,问题是知道哪些对象实现 IDisposable...不幸的是,除了文档之外,没有自动方法可以知道。尽管我相信有一个 Fxcop 设置可以检查在使用之外使用的 IDisposables。

The purpose of IDisposable is to enable objects that interact with unmanaged resources (like files, databases, or graphics contexts) to clean up after themselves. A using statement is a convenient shorthand for the following construct

var disposable = new MemoryStream();
try
{
  //do some work with the disposable object
}
finally
{
  if (disposable!=null)
     disposable.Dispose();  
}

The problem of course is knowing which objects implement IDisposable...unfortunately there is no automated way to know besides the docs. Although I believe there is an Fxcop setting that will check for IDisposables used outside of a using.

猫弦 2024-09-15 05:17:08

您不必担心在 using 块下使用哪些类。如果您在 using 语句下使用的未实现 IDisposbale 那么它将向您显示红色/蓝色波浪。这样你就知道它缺少一次性的接口。据我使用过的几乎所有框架类都实现了 Idisposable。但在自定义类中,您需要实现

you need not to worry about using what classes under using blocks. If the you have used under using statement doesnot implements IDisposbale then it will show you red/blue wave. So that you can come to knwo that its lacking idisposable interface. And as far as i have used almost all classes of framework has Idisposable implemented. but in custom class , you need to implement

萝莉病 2024-09-15 05:17:08

使用 using 调用的类有:

  • Streams
  • 数据库连接、命令和数据读取器
  • Readers 和 Writers

还有很多其他类您也应该 Dispose,但上面的那些经常使用,经常使用。使用范围狭窄。

是的 - 不使用 using 和不调用 dispose 会出现问题。经典的 Web 应用程序不会关闭与数据库的连接,在保持连接打开时有效地从数据库服务器中吸取资源。

A ready-reckoner of classes to call with using is:

  • Streams
  • Database connections, commands and data readers
  • Readers and Writers

There are many many more classes which you should also Dispose, but those above are frequently used, often in narrow usage scope.

Yes - there are issues with not using using and not calling dispose. A classic is a web app which does not close its connections to a database, effectively sucking resources from the database server as it holds connections open.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文