我正在尝试创建一个类似于 Rust 的类型Result
或哈斯克尔的Either
到目前为止我已经做到了:
public struct Result<TResult, TError>
where TResult : notnull
where TError : notnull
{
private readonly OneOf<TResult, TError> Value;
public Result(TResult result) => Value = result;
public Result(TError error) => Value = error;
public static implicit operator Result<TResult, TError>(TResult result)
=> new Result<TResult, TError>(result);
public static implicit operator Result<TResult, TError>(TError error)
=> new Result<TResult, TError>(error);
public void Deconstruct(out TResult? result, out TError? error)
{
result = (Value.IsT0) ? Value.AsT0 : (TResult?)null;
error = (Value.IsT1) ? Value.AsT1 : (TError?)null;
}
}
鉴于这两种类型的参数都被限制为notnull
,为什么它会抱怨(任何有可空类型参数的地方?
在其后签名):
必须知道可为空类型参数是值类型或不可为空引用类型。考虑添加“类”、“结构”或类型约束。
?
我在 .NET Core 3 上使用 C# 8,并启用了可空引用类型。
基本上,您要求的东西无法在 IL 中表示。可空值类型和可空引用类型是非常不同的东西,虽然它们在源代码中看起来很相似,但 IL 却非常不同。值类型的可为空版本T
是一种不同的类型(Nullable<T>
) 而引用类型的可为空版本T
is the same类型,其属性告诉编译器期望什么。
考虑这个更简单的例子:
public class Foo<T> where T : notnull
{
public T? GetNullValue() =>
}
出于同样的原因,这是无效的。
如果我们约束T
是一个结构体,那么生成的 ILGetNullValue
方法的返回类型为Nullable<T>
.
如果我们约束T
为不可为 null 的引用类型,则为以下生成的 ILGetNullValue
方法的返回类型为T
,但具有可空性方面的属性。
编译器无法为具有两者返回类型的方法生成 ILT
and Nullable<T>
同时。
这基本上是可空引用类型根本不是 CLR 概念的结果 - 它只是编译器的魔法,可以帮助您在代码中表达意图并让编译器在编译时执行一些检查。
但错误消息并不像想象的那么清楚。T
已知为“值类型或不可为空的引用类型”。更精确(但明显更冗长)的错误消息是:
可以为 null 的类型参数必须是值类型,或者是不可为 null 的引用类型。考虑添加“类”、“结构”或类型约束。
那时,错误将合理地适用于我们的代码 - 类型参数不是“已知是值类型”,也不是“已知是不可为空的引用类型”。已知是两者之一,但编译器需要知道which.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)