猿问

具有可为空引用类型的输出参数

我已经为我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;


无法将 null 文字转换为不可为 null 的引用或不受约束的类型参数


我不可能将泛型参数限制T为classor struct。


例如,如果我将泛型参数限制为 ,则class无法生成Option<int?>实例,因为Nullable<int>类型是 astruct本身。通过后缀将 out 参数声明为可为空也不?是看起来的解决方案。


对我来说,在这个阶段,类型系统有些破损或没有彻底考虑过。Nullable 应该是 aclass或者需要有一个通用参数限制,例如:


public static bool TryGetValue<T>(this Option<T> option, out T value) 

    where T : nullable [...]

是否有另一种可能适合此问题的方法?我错过了什么?


摇曳的蔷薇
浏览 254回答 2
2回答

ITMISS

使用MaybeNullWhenAttribute或NotNullWhenAttribute。我推荐MaybeNullWhen,因为它甚至适用于不受结构或引用类型约束的类型参数。public static bool TryGetValue<T>(this Option<T> option, [MaybeNullWhen(false)] out T value){&nbsp; &nbsp; if (option is Some<T> some)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; value = some.Value;&nbsp; &nbsp; &nbsp; &nbsp; return true;&nbsp; &nbsp; }&nbsp; &nbsp; value = default;&nbsp; &nbsp; return false;}用法:if(option.TryGetValue(out var value)){&nbsp; &nbsp; value.SomeMethod(); // no warning - value is known to be non-null here}value.SomeMethod(); // warning - value may be null here.该属性在 .Net 标准 2.1/.new core 3.0 之前不可用,但如果它不可用,您可以自己手动定义它。确保它是内部的,否则如果另一个库也将它定义为公共并且有人从这两个库继承它会导致冲突:namespace System.Diagnostics.CodeAnalysis{&nbsp; &nbsp; /// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter may be null even if the corresponding type disallows it.</summary>&nbsp; &nbsp; [AttributeUsage(AttributeTargets.Parameter, Inherited = false)]&nbsp; &nbsp; internal sealed class MaybeNullWhenAttribute : Attribute&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; /// <summary>Initializes the attribute with the specified return value condition.</summary>&nbsp; &nbsp; &nbsp; &nbsp; /// <param name="returnValue">&nbsp; &nbsp; &nbsp; &nbsp; /// The return value condition. If the method returns this value, the associated parameter may be null.&nbsp; &nbsp; &nbsp; &nbsp; /// </param>&nbsp; &nbsp; &nbsp; &nbsp; public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;&nbsp; &nbsp; &nbsp; &nbsp; /// <summary>Gets the return value condition.</summary>&nbsp; &nbsp; &nbsp; &nbsp; public bool ReturnValue { get; }&nbsp; &nbsp; }(取自https://github.com/dotnet/runtime/blob/6077cf01f951a711a26a8d5970b211b6031b5158/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs#L45-L60)

侃侃尔雅

到目前为止,使用 C# 8.0 还没有完全通用的解决方案。[NotNullWhen()]属性是向前迈出的一步,但随后我们将遇到以下情况:可空类型参数必须已知为值类型或不可空引用类型。考虑添加“类”、“结构”或类型约束。我想说这是现在可以为空的一个主要痛点。我希望它会在 8.1 或其他东西中得到解决......相关讨论 -&nbsp;https://github.com/dotnet/cshaplang/issues/2194&nbsp;-允许泛型方法指定 T?不限于 class 或 struct。where作为一种解决方法,可以制作具有所需约束的多个扩展方法副本以涵盖所有可能的类型。由于问题#1628已修复,现在可以在单个扩展类中包含所有重载。但它仍然需要为每个独立的通用输出参数增加一倍的扩展方法数量。哎呀!
随时随地看视频慕课网APP
我要回答