带有可空引用类型的参数

时间:2018-12-13 10:00:25

标签: c# .net-core nullable c#-8.0

我已经为我的某些项目实现了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限制为classstruct

例如,如果我将通用参数限制为class,则由于Option<int?>类型本身是Nullable<int>,因此无法生成struct实例。通过后缀?将out参数声明为可为空也似乎不是解决方案。

对我来说,此阶段的字体系统有些破损或未经过全面考虑。 Nullable应该是一个class,或者需要一个通用的参数限制,例如:

public static bool TryGetValue<T>(this Option<T> option, out T value) 
    where T : nullable [...]

是否存在另一种适合该问题的方法?我想念什么?

2 个答案:

答案 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实际上是可为空的)类型,在这种情况下还是可以的。