Khh*_*Khh 21 c# try-catch yield-return .net-3.5
我有一段代码:
using (StreamReader stream = new StreamReader(file.OpenRead(), Encoding))
{
char[] buffer = new char[chunksize];
while (stream.Peek() >= 0)
{
int readCount = stream.Read(buffer, 0, chunksize);
yield return new string(buffer, 0, readCount);
}
}
Run Code Online (Sandbox Code Playgroud)
现在我必须使用try-catch块来包围它
try
{
using (StreamReader stream = new StreamReader(file.OpenRead(), Encoding))
{
char[] buffer = new char[chunksize];
while (stream.Peek() >= 0)
{
int readCount = stream.Read(buffer, 0, chunksize);
yield return new string(buffer, 0, readCount);
}
}
}
catch (Exception ex)
{
throw ExceptionMapper.Map(ex, file.FullName)
}
Run Code Online (Sandbox Code Playgroud)
我看不出有什么方法可以做我想做的事.
编辑 该方法具有签名
public IEnumerable<string> ReadPieces(int pieces)
Run Code Online (Sandbox Code Playgroud)
我需要一个try catch
与该呼叫ExceptionMapper
的catch
情况.所有呼叫者都推迟使用该方法.
我必须抓住的例外情况来自这些电话
File.OpenRead()
stream.Read()
Run Code Online (Sandbox Code Playgroud)
小智 31
这是一个代码片段,适用于我(我没有达到错误条件).
while (true)
{
T ret = null;
try
{
if (!enumerator.MoveNext())
{
break;
}
ret = enumerator.Current;
}
catch (Exception ex)
{
// handle the exception and end the iteration
// probably you want it to re-throw it
break;
}
// the yield statement is outside the try catch block
yield return ret;
}
Run Code Online (Sandbox Code Playgroud)
Jas*_*ban 14
因为您希望在枚举期间保持Stream打开并处理异常并正确关闭文件句柄,我认为您不能使用常规枚举快捷方式(迭代器块,yield-return/yield-打破).
相反,只需执行编译器为您完成的操作并添加一些:
通过自己实现IEnumerator,您还可以添加IDisposable
public class LazyStream : IEnumerable<string>, IDisposable
{
LazyEnumerator le;
public LazyStream(FileInfo file, Encoding encoding)
{
le = new LazyEnumerator(file, encoding);
}
#region IEnumerable<string> Members
public IEnumerator<string> GetEnumerator()
{
return le;
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return le;
}
#endregion
#region IDisposable Members
private bool disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
if (le != null) le.Dispose();
}
disposed = true;
}
}
#endregion
class LazyEnumerator : IEnumerator<string>, IDisposable
{
StreamReader streamReader;
const int chunksize = 1024;
char[] buffer = new char[chunksize];
string current;
public LazyEnumerator(FileInfo file, Encoding encoding)
{
try
{
streamReader = new StreamReader(file.OpenRead(), encoding);
}
catch
{
// Catch some generator related exception
}
}
#region IEnumerator<string> Members
public string Current
{
get { return current; }
}
#endregion
#region IEnumerator Members
object System.Collections.IEnumerator.Current
{
get { return current; }
}
public bool MoveNext()
{
try
{
if (streamReader.Peek() >= 0)
{
int readCount = streamReader.Read(buffer, 0, chunksize);
current = new string(buffer, 0, readCount);
return true;
}
else
{
return false;
}
}
catch
{
// Trap some iteration error
}
}
public void Reset()
{
throw new NotSupportedException();
}
#endregion
#region IDisposable Members
private bool disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
if (streamReader != null) streamReader.Dispose();
}
disposed = true;
}
}
#endregion
}
}
Run Code Online (Sandbox Code Playgroud)
我没有对此进行测试,但我认为它很接近.
像这样使用:
using (var fe = new LazyStream(new FileInfo("c:\\data.log"), Encoding.ASCII))
{
foreach (var chunk in fe)
{
Console.WriteLine(chunk);
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:我完全忘记添加try-catch块放置.哎呀.
您不能yield
在try/catch块中使用构造.将try块限制为可以抛出的代码,而不是全部代码.如果你不能做到这一点,那你就不走运了 - 你需要进一步抓住它.
编辑 - 由于评论中详细说明的原因,这个答案实际上是不正确的 - "只有枚举器生成被包装,而不是迭代本身." - 但我在这里留下这个答案,作为一个例子,说明有时可能看起来有效的东西并不是由于语言的错综复杂.
把它看作一个警示故事 - 我要感谢你们.=)
这是一个选项 - 将您的方法分为两种方法,一种是公共方法,另一种是私有方式.public方法是一个包装器(使用try/catch)围绕私有方法的调用,这是您的生成器.例如:
public IEnumerable<string> YourFunction(...)
{
try
{
return _yourFunction(...);
}
catch (Exception e)
{
throw ExceptionMapper.Map(e, file.FullName);
}
}
private IEnumerable<string> _yourFunction(...)
{
// Your code here
}
Run Code Online (Sandbox Code Playgroud)
这将允许您的用户依赖具有内置异常处理的生成器.此外,您可以在公共方法中对输入执行更多验证,由于输入错误而根据需要抛出任何异常,并在调用方法时立即执行这些验证,而不是等待第一次枚举枚举.