Jad*_*ias 36 .net c# linq exception-handling exception
例:
myEnumerable.Select(a => ThisMethodMayThrowExceptions(a));
Run Code Online (Sandbox Code Playgroud)
即使抛出异常,如何使其工作?就像带有默认值的try catch块一样,会抛出异常......
Ste*_*ger 40
myEnumerable.Select(a =>
{
try
{
return ThisMethodMayThrowExceptions(a));
}
catch(Exception)
{
return defaultValue;
}
});
Run Code Online (Sandbox Code Playgroud)
但实际上,它有一些气味.
关于lambda语法:
x => x.something
Run Code Online (Sandbox Code Playgroud)
是一种捷径,可以写成
(x) => { return x.something; }
Run Code Online (Sandbox Code Playgroud)
Jon*_*eet 18
调用具有try/catch的投影:
myEnumerable.Select(a => TryThisMethod(a));
...
public static Bar TryThisMethod(Foo a)
{
try
{
return ThisMethodMayThrowExceptions(a);
}
catch(BarNotFoundException)
{
return Bar.Default;
}
}
Run Code Online (Sandbox Code Playgroud)
不可否认,我很少想使用这种技术.感觉就像是滥用例外,但有时会有API让你别无选择.
(我几乎肯定会把它放在一个单独的方法中,而不是把它作为lambda表达式"内联".)
如果您需要Expression而不是lambda函数(例如,从IQueryable中选择时),您可以使用以下内容:
public static class ExpressionHelper
{
public static Expression<Func<TSource, TResult>> TryDefaultExpression<TSource, TResult>(Expression<Func<TSource, TResult>> success, TResult defaultValue)
{
var body = Expression.TryCatch(success.Body, Expression.Catch(Expression.Parameter(typeof(Exception)), Expression.Constant(defaultValue, typeof (TResult))));
var lambda = Expression.Lambda<Func<TSource, TResult>>(body, success.Parameters);
return lambda;
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
[Test]
public void Test()
{
var strings = new object [] {"1", "2", "woot", "3", Guid.NewGuid()}.AsQueryable();
var ints = strings.Select(ExpressionHelper.TryDefaultExpression<object, int>(x => Convert.ToInt32(x), 0));
Assert.IsTrue(ints.SequenceEqual(new[] {1, 2, 0, 3, 0}));
}
Run Code Online (Sandbox Code Playgroud)
当我很快想要尝试/捕获每个迭代时,我有一个小扩展 IEnumerable<T>
用法
public void Test()
{
List<string> completedProcesses = initialEnumerable
.SelectTry(x => RiskyOperation(x))
.OnCaughtException(exception => { _logger.Error(exception); return null; })
.Where(x => x != null) // filter the ones which failed
.ToList();
}
Run Code Online (Sandbox Code Playgroud)
扩展名
public static class OnCaughtExceptionExtension
{
public static IEnumerable<SelectTryResult<TSource, TResult>> SelectTry<TSource, TResult>(this IEnumerable<TSource> enumerable, Func<TSource, TResult> selector)
{
foreach (TSource element in enumerable)
{
SelectTryResult<TSource, TResult> returnedValue;
try
{
returnedValue = new SelectTryResult<TSource, TResult>(element, selector(element), null);
}
catch (Exception ex)
{
returnedValue = new SelectTryResult<TSource, TResult>(element, default(TResult), ex);
}
yield return returnedValue;
}
}
public static IEnumerable<TResult> OnCaughtException<TSource, TResult>(this IEnumerable<SelectTryResult<TSource, TResult>> enumerable, Func<Exception, TResult> exceptionHandler)
{
return enumerable.Select(x => x.CaughtException == null ? x.Result : exceptionHandler(x.CaughtException));
}
public static IEnumerable<TResult> OnCaughtException<TSource, TResult>(this IEnumerable<SelectTryResult<TSource, TResult>> enumerable, Func<TSource, Exception, TResult> exceptionHandler)
{
return enumerable.Select(x => x.CaughtException == null ? x.Result : exceptionHandler(x.Source, x.CaughtException));
}
public class SelectTryResult<TSource,TResult>
{
internal SelectTryResult(TSource source, TResult result, Exception exception)
{
Source = source;
Result = result;
CaughtException = exception;
}
public TSource Source { get; private set; }
public TResult Result { get; private set; }
public Exception CaughtException { get; private set; }
}
}
Run Code Online (Sandbox Code Playgroud)
我们最终可以通过SkipOnException扩展来进一步,例如,接受可选的异常处理程序.