gpt4 book ai didi

c# - 是否有类似(值或错误)可区分联合的 .NET 类型?

转载 作者:太空狗 更新时间:2023-10-29 17:50:23 25 4
gpt4 key购买 nike

在 C# 中,我希望可以选择以更“函数式”的方式处理错误,而不是始终使用默认的异常抛出模型。在某些情况下,抛出模型很棒,因为它允许您在发生意外情况时强制停止执行代码。然而, throw 模型有几个主要缺点:

  1. 异常抛出基本上是颠覆主控制流系统的应用程序控制流的整个辅助系统。当一个方法被调用时,它的主体被执行,然后有效地控制返回给调用者,不管它是否是由于 return 引起的。或 throw陈述。如果控制从 throw 返回给调用者声明,如果没有合适的try,控制将立即转移到它的调用者/catch在适用范围;而如果控制从 return 返回声明,控制继续正常进行。我知道实现比这更复杂和微妙,但我认为这是一个适当的概念性总结。这种双重系统通常在设计时和运行时以不同的方式令人困惑。
  2. 抛出系统在并行或异步场景中变得更加笨拙,正如 System.Threading.Tasks.Task 对错误的处理所看到的那样. Task 抛出的任何异常执行存储在 AggregateException 中并通过 Task.Exception 访问调用代码的属性。所以虽然 Task s 的执行可能会中止,调用代码必须使用正常的 C# 控制流查找存储在对象属性中的错误。
  3. 除了 XML 注释之外,没有关于方法是否可能抛出异常或可能抛出哪些异常的元数据。异常表现为方法输出的另一种形式,但在很大程度上被类型系统忽略了。例如,方法 int Divide(int x, int y)可能导致整数或 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}}}";
}

以及问题:

  1. 是否已经有类似 Fallible<T> 的东西了?对于.NET?也许是任务并行库、响应式扩展或 F# 核心库中的类?
  2. 上述实现是否存在重大缺陷?
  3. 是否有任何我可能忽略的控制流概念问题?

最佳答案

虽然 FSharp.Core 确实包含对选项的支持,但 BCL 中并没有内置类似的东西,这提供了另一种机制,您可以通过它来避免异常处理。

Language Ext项目确实包含 Try<T>类型与您所描述的非常相似。此外,它还有一个 C# 友好的 Option<T>对选项的操作使用伪模式匹配。

关于c# - 是否有类似(值或错误)可区分联合的 .NET 类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40812057/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com