Jam*_*aix 10 .net c# f# functional-programming exception-handling
在C#中,我希望能够以更"功能"的方式处理错误,而不是总是使用默认的异常抛出模型.在某些情况下,投掷模型很棒,因为它允许您强制代码在发生意外情况时停止执行.但是,投掷模型有几个主要缺点:
return
还是throw
语句.如果控制从throw
语句返回给调用者,如果没有适当的try
/ catch
在范围内,控件将立即移动到其调用者; 而如果控制权从一个return
陈述中返回,则控制权继续正常进行.我知道实现方式比这更复杂和微妙,但我认为这是一个恰当的概念性总结.在设计时和运行时,这种双系统通常会以不同的方式混淆.System.Threading.Tasks.Task
.Task
执行抛出的任何异常都存储在一个并由调用代码AggregateException
通过Task.Exception
属性访问.因此,当Task
s执行可能被中止时,调用代码必须使用正常的C#控制流来查找存储在对象属性中的错误.int Divide(int x, int y)
可能导致整数或a DivideByZeroException
,但此方法的签名不建议任何有关错误的内容.相反,我经常听到有关Java检查异常的抱怨,其中一个方法可以抛出的每个特定异常类型必须添加到其签名中,这可能变得非常冗长.对我来说,最简单的中间地点是泛型类型Nullable<T>
,包含值或异常.这样的方法Divide
会有这个签名:Fallible<int> Divide(int x, int y)
.然后,使用该结果的任何操作都需要处理错误情况.方法也可以采用Fallible
参数来更容易链接.这是Fallible
我概述的一个实现:
public class Fallible<T> : IEquatable<Fallible<T>> {
#region Constructors
public Fallible() {
//value defaults to default(T)
//exception defaults to null
}
public Fallible(T value) : this() {
this.value = value;
}
public Fallible(Exception error) : this() {
if (error == null) throw new ArgumentNullException(nameof(error));
Error = error;
}
public Fallible(Func<T> getValue) : this() {
if (error == null) throw new ArgumentNullException(nameof(getValue));
try {
this.value = getValue();
}
catch(Exception x) {
Error = x;
}
}
#endregion
#region Properties
public T Value {
get {
if (!HasValue) throw new InvalidOperationException("Cannot get Value if HasValue is false.");
return value;
}
}
private T value;
public Exception Error { get; }
public bool HasValue => Error == null;
#endregion
#region Equality
public bool Equals(Fallible<T> other) => (other != null)
&& Equals(Error, other.Error)
&& Equals(Value, other.Value);
public override bool Equals(object obj) => Equals(obj as Fallible<T>);
public static bool operator ==(Fallible<T> a, Fallible<T> b) {
if (a == null) return b == null;
return a.Equals(b);
}
public static bool operator !=(Fallible<T> a, Fallible<T> b) {
if (a == null) return b != null;
return !a.Equals(b);
}
public override int GetHashCode() =>
HasValue
? Value.GetHashCode()
: Error.GetHashCode();
#endregion
public override string ToString() =>
HasValue
? $"Fallible{{{Value}}}"
: $"Fallible{{{Error.GetType()}: {Error.Message}}}";
}
Run Code Online (Sandbox Code Playgroud)
问题是:
Fallible<T>
.NET 这样的东西?也许是任务并行库,Reactive Extensions或F#核心库中的一个类?