Pet*_*old 13 c# language-features design-patterns idisposable
您对如何在.Net中实施一次性物品有何看法?你如何解决实现IDisposable类的重复性?
我觉得IDisposable类型不是他们应该去过的一流公民.太多是由开发人员的怜悯.
具体来说,我想知道是否应该在语言和工具方面提供更好的支持,以确保一次性物品的正确实施和妥善处理.
例如,在C#中,如果需要实现一次性语义的类可以像这样声明:
public class disposable MyDisposableThing
{
~MyDisposableThing()
{
// Dispose managed resources
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,编译器可以轻松生成IDisposable接口的实现.析构函数~MyDisposableThing可以转换为应该释放托管资源的实际Dispose方法.
中间C#代码如下所示:
public class MyDisposableThing : IDisposable
{
private void MyDisposableThingDestructor()
{
// Dispose my managed resources
}
~MyDisposableThing()
{
DisposeMe(false);
}
public void Dispose()
{
DisposeMe(true);
GC.SuppressFinalize(this);
}
private bool _disposed;
private void DisposeMe(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
// Call the userdefined "destructor"
MyDisposableThingDestructor();
}
}
_disposed = true;
}
}
Run Code Online (Sandbox Code Playgroud)
这样可以实现更清晰的代码,更少的样板处理代码以及处理托管资源的一致方式.对于边缘情况和非托管资源,仍然支持手动实现IDisposable.
确保实例得到妥善处理是另一项挑战.请考虑以下代码:
private string ReadFile(string filename)
{
var reader = new StreamReader();
return reader.ReadToEnd(filename);
}
Run Code Online (Sandbox Code Playgroud)
reader变量永远不会超出方法的范围,但必须等待GC处理它.在这种情况下,编译器可能会引发StreamReader对象未显式处理的错误.此错误将提示开发人员将其包装在using语句中:
private string ReadFile(string filename)
{
using (var reader = new StreamReader())
{
return reader.ReadToEnd(filename);
}
}
Run Code Online (Sandbox Code Playgroud)
Eri*_*ert 24
一个常用的原则是"需要设计模式来解决语言缺陷".这是该原则的一个例子.我们需要一次性模式,因为语言不会给你.
我同意,可处置可能已经抬高了"模式"的世界,进入C#语言正确的,因为我们有,比如说,财产getter和setter方法(这是具有getter和setter方法的模式的标准化),或事件做(它标准化了存储委托的想法,并在有趣的事情发生时调用它.)
但是语言设计很昂贵,并且可以应用有限的努力.因此,我们试图找到最有用,最引人注目的模式,以适当的语言.我们试图找到一种方式,这种方式不仅方便,而且实际上为语言增添了更多的表达能力.例如,LINQ将过滤,投影,连接,分组和排序数据的概念转换为适当的语言,这为语言增添了许多表达能力.
虽然这当然是一个好主意,但我认为它不符合标准.我同意这将是一个很好的方便,但它不会启用任何真正丰富的新方案.
除了其他答案之外,还有一个问题是这应该实现多少以及人们应该从中得到什么?说我像这样宣布我的课:
public disposable class MyClass
{
readonly AnotherDisposableObject resource = new AnotherDisposableObject();
~MyClass()
{
this.resource.Dispose();
}
public void DoStuff()
{
this.resource.SomeMethod();
}
}
Run Code Online (Sandbox Code Playgroud)
那么如果在实例DoStuff 后调用的调用者被处理掉,你会发生什么?应该编译器自动插入类似的东西
if (this.disposed) throw new ObjectDisposedException();
Run Code Online (Sandbox Code Playgroud)
在每个方法的开头,因为你已经宣布该类是一次性的?
如果是这样,那么在处理对象之后显式允许调用方法的情况怎么样(例如MemoryStream.GetBuffer)?你是否必须引入一个新的关键字,向编译器表明这一点,例如public useafterdispose void ...?
如果没有,那么如何向人们解释新关键字为您实现一些样板代码,但是他们仍然需要编写代码来检查对象是否在每个方法中处理?而且,他们怎么能检查这一点,因为关于对象是否已被处置的所有状态信息都是自动生成的!现在,他们需要在~MyClass方法中跟踪自己的标志,这将取消编译器应该为您完成的一半工作.
我认为作为一种特定的语言模式,概念中存在太多漏洞,并且它只试图解决一个特定问题.现在,能够以通用方式解决这一整类问题的是mixins(即一次性mixin),这种语言特征通常可以重用于不同的概念(例如Equatable mixin,Comparable mixin等).那是我的钱去的地方.
就个人而言,我认为IDisposable在当前版本的.NET中支持相当不错.using关键字的存在几乎使它成为我的第一类构造.
我承认有一定数量的样板代码,但不足以保证新的语言功能.(自动实现的属性是一个很好的例子,这个功能正在被引入.)你错过了帖子中的一个重点,即这个"样板"代码并不总是你所需要的.主要是,您需要在块外部处理非托管资源if (disposing).
当然,析构函数(~MyDisposableThing)和无参数Dispose()方法是真正的样板,并且可以被语言关键字的用户消除,正如您所建议的那样 - 但是我再次确定引入一个实际的新关键字对于少数人来说是必要的.代码行.
我当然看到你在这里提出的观点,并在某种程度上同情它.(我确信如果你的建议成为语言规范的一部分,那么编码人员就不会抱怨.)然而,当代码行数相当有限时,它不可能说服.NET开发团队,其中一些可以说是有争议的相当特定于上下文(因此不是样板).