我已经为我的某些项目实现了Option
类型,
public abstract Option<T> {}
public class None<T> : Option<T>
public class Some<T> : Option<T>
{
public T Value { get; }
public Some(T value)
{
Value = value;
}
}
为了确定选项是否包含值,我使用了这种扩展方法,该方法利用了模式匹配:
public static bool TryGetValue<T>(this Option<T> option, out T value)
{
if (option is Some<T> some)
{
value = some.Value;
return true;
}
value = default;
return false;
}
我现在收到针对return default;
的以下警告
无法将空文字转换为不可为空的引用或不受约束的类型参数
我不可能将通用参数T
限制为class
或struct
。
例如,如果我将通用参数限制为class
,则由于Option<int?>
类型本身是Nullable<int>
,因此无法生成struct
实例。通过后缀?
将out参数声明为可为空也似乎不是解决方案。
对我来说,此阶段的字体系统有些破损或未经过全面考虑。 Nullable应该是一个class
,或者需要一个通用的参数限制,例如:
public static bool TryGetValue<T>(this Option<T> option, out T value)
where T : nullable [...]
是否存在另一种适合该问题的方法?我想念什么?
答案 0 :(得分:1)
使用C#8.0到目前为止,还没有一种完美的通用解决方案。
[NotNullWhen()]
属性是前进的一步,但随后我们将遇到以下问题:
必须知道可空类型参数是值类型或不可空引用类型。考虑添加“类”,“结构”或类型约束。
我想说这是现在可以为空的主要痛点。我希望它将在8.1或更高版本中得到解决...
相关讨论-https://github.com/dotnet/csharplang/issues/2194-允许使用通用方法指定T?而不限制类或结构。
作为一种解决方法,可以制作具有所需where
约束的多个扩展方法副本,以涵盖所有可能的类型。
由于问题#1628已得到解决,现在可以在单个扩展类中包含所有重载。但是对于每个独立的通用out参数,仍然需要将扩展方法的数量加倍。 kes!
快速浏览,我找不到特定于out参数的未解决问题。如果尚未完成,可能值得将此特殊用例带入csharplang github问题。
更新:我在上述问题上做出了一个comment,并对此表示赞同。
答案 1 :(得分:0)
如果只想编译它,则可以使用!
运算符:
public static bool TryGetValue<T>(this Option<T> option, out T value)
{
if (option is Some<T> some)
{
value = some.Value;
return true;
}
value = default!;
return false;
}
不幸的是,这意味着T即使不是也不能为null。
但是,如果确保始终正确使用Try模式(即在使用out参数之前检查TryGetValue
的返回值),则永远不会观察到该值为空(除非T实际上是可为空的)类型,在这种情况下还是可以的。