Edu*_*ual 3 c# dispose enumerator
好吧,这里有一段很糟糕的代码:
public class Log : CachingProxyList<Event> {
public static Log FromFile(String fullPath) {
using (FileStream fs = new FileStream(fullPath, FileMode.Open, FileAccess.Read)) {
using (StreamReader sr = new StreamReader(fs)) {
return new Log(sr);
}
}
}
public Log(StreamReader stream)
: base(Parser.Parse(Parser.Tokenize(stream))) {
/* Here goes some "magic", the whole reason for this
* class to exist, but not really relevant to the issue */
}
}
Run Code Online (Sandbox Code Playgroud)
现在问题的一些背景:
CachingProxyList是一个IEnumerable<T>提供自定义"缓存"枚举器的实现:它接受一个IEnumerable<T>构造函数,最初通过它进行枚举,但是将每个项目保存在私有List<T>字段上,以便在继续进行实际解析之前进行进一步的迭代(而不是不时地解析;或者只是解析一个巨大的日志来查询它的一小部分).
请注意,实际上需要进行此优化,并且大部分已经在使用(如果我删除了using语句,除了泄漏的文件句柄外,一切都很顺利).
这两个Parse和Tokenize是迭代器块(据我所知,唯一明智的方法我可以延期执行和干净的代码在同一时间); 他们的签名是IEnumerable<Event> Parse(IEnumerable<Token>)和IEnumerable<Token> Tokenize(StreamReader).他们的逻辑与这个问题无关.
逻辑流程非常明确; 并且代码的每个部分的意图相当明显; 但是这些using块与整个延迟执行事物不相处(当我通过我的Log对象枚举时,using已经退出并且流被丢弃了,因此Tokenize试图从它中读取可悲的崩溃).
我可以承受锁定文件(开放流)相当长的时间,但迟早我将不得不关闭它.由于我无法真正使用usings,因此我必须明确处理这些流.
问题是:我应该在哪里拨打电话Dispose()?是否有任何常见的习惯用法来处理这些情景?我不想这样做"旧方式"(在几个地方释放资源,不得不在任何时候审查每个版本,一小部分代码在某处改变,等等).
我的第一个想法是让Log类成为一次性的,所以它的构造函数可以采用文件名并在类中进行所有资源管理(只需要消费者Log在完成后处理它自己),但是我看不到创建的方法并在调用base构造函数之前保存流(对于生成该构造函数的参数的调用,该流是必需的).
注意:CachingProxyList除非严格要求,否则不应触及(我希望保持通用性以使其可重复使用).特别地,构造函数对于强制实现其余实现严重依赖的一些不变量是必不可少的(例如内部枚举器对象永远不为null).其他一切,OTOH,应该是公平的游戏.
如果您已经阅读本文,请感谢您的耐心等待,并提前感谢您提供的任何帮助;).
IDisposable接口).例如流,数据库连接等Dispose()该资源Dispose()其资源或不知道何时调用它,那么它需要实现IDisposable接口本身并Dispose()在其中调用其资源.以上陈述可能有例外,但这是一般规则.示例是StreamWriter接收流(实现IDisposable接口)并强制它实现IDisposable接口本身 - 因为它不知道何时处置它.
在你的情况下是一样的.你的班级使用一次性资源,而不知道何时处置它 - 或者这就是我的假设.这将使它实现IDisposable接口.你Log班上的客户必须打电话Dispose()给你的班级.
正如您所看到的,这成为一个链,而非一次性客户端将不得不在其使用的资源上调用dispose,并且该资源将处置其资源等...
| 归档时间: |
|
| 查看次数: |
189 次 |
| 最近记录: |