可空的引用类型:如何指定"T"?类型而不限制类或结构 [英] Nullable reference types: How to specify "T?" type without constraining to class or struct

查看:308
本文介绍了可空的引用类型:如何指定"T"?类型而不限制类或结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个具有T类型成员的泛型类. T可以是类,可为空的类,结构或可为空的结构.所以基本上什么都可以.这是一个简化的示例,显示了我的问题:

I want to create a generic class that has a member of type T. T may be a class, a nullable class, a struct, or a nullable struct. So basically anything. This is a simplified example that shows my problem:

#nullable enable

class Box<T> {
    public T Value { get; }

    public Box(T value) {
        Value = value;
    }

    public static Box<T> CreateDefault()
        => new Box<T>(default(T));
}

由于使用了新的#nullable enable功能,我收到以下警告:Program.cs(11,23): warning CS8653: A default expression introduces a null value when 'T' is a non-nullable reference type.

Due to using the new #nullable enable feature I get the following warning: Program.cs(11,23): warning CS8653: A default expression introduces a null value when 'T' is a non-nullable reference type.

此警告对我来说很有意义.然后,我尝试通过在属性和构造函数参数中添加?来修复该问题:

This warning makes sense to me. I then tried to fix it by adding a ? to the property and constructor parameter:

#nullable enable

class Box<T> {
    public T? Value { get; }

    public Box(T? value) {
        Value = value;
    }

    public static Box<T> CreateDefault()
        => new Box<T>(default(T));
}

但是现在我得到两个错误:

But now I get two errors instead:

Program.cs(4,12): error CS8627: A nullable type parameter must be known to be a value type or non-nullable reference type. Consider adding a 'class', 'struct', or type constraint.
Program.cs(6,16): error CS8627: A nullable type parameter must be known to be a value type or non-nullable reference type. Consider adding a 'class', 'struct', or type constraint.

但是,我不想添加约束.我不在乎T是类还是结构.

However, I don't want to add a constraint. I don't care if T is a class or a struct.

一个明显的解决方案是将有问题的成员包装在#nullable disable指令下.但是,像#pragma warning disable一样,除非有必要,否则我想避免这样做.是否有另一种方法可以在不禁用可空性检查或CS8653警告的情况下编译我的代码?

An obvious solution is to wrap the offending members under a #nullable disable directive. However, like #pragma warning disable, I'd like to avoid doing that unless it's necessary. Is there another way in getting my code to compile without disabling the nullability checks or the CS8653 warning?

$ dotnet --info
.NET Core SDK (reflecting any global.json):
 Version:   3.0.100-preview4-011223
 Commit:    118dd862c8

推荐答案

如有关此问题的评论中所述,您可能需要考虑一下带有默认值的Box<string>是否有效.可为空的上下文,并可能相应地调整您的API表面.为了使包含默认值的实例有效,类型可能必须为Box<string?>.但是,在某些情况下,您将需要指定属性,方法返回值或参数等仍然为空,即使它们具有不可为空的引用类型.如果您属于该类别,则可能需要使用与可空性相关的属性.

As discussed in the comments on this question, you will probably need to take some thought as to whether a Box<string> with a default value is valid or not in a nullable context and potentially adjust your API surface accordingly. Perhaps the type has to be Box<string?> in order for an instance containing a default value to be valid. However, there are scenarios where you will want to specify that properties, method returns or parameters, etc. could still be null even though they have non-nullable reference types. If you are in that category, you will probably want to make use of nullability-related attributes.

MaybeNull AllowNull 属性已引入.NET Core 3中以处理这种情况.

The MaybeNull and AllowNull attributes have been introduced to .NET Core 3 to handle this scenario.

这些属性的某些特定行为仍在发展,但是基本思想是:

Some of the specific behaviors of these attributes are still evolving, but the basic idea is:

  • [MaybeNull]表示某项(读取字段或属性,方法返回等)的输出可能是null.
  • [AllowNull]表示对某事物(写字段或属性,方法参数等)的输入可能是null.
  • [MaybeNull] means that the output of something (reading a field or property, a method return, etc.) could be null.
  • [AllowNull] means that the input to something (writing a field or property, a method parameter, etc.) could be null.
#nullable enable
using System.Diagnostics.CodeAnalysis;

class Box<T>
{
    // We use MaybeNull to indicate null could be returned from the property,
    // and AllowNull to indicate that null is allowed to be assigned to the property.
    [MaybeNull, AllowNull]
    public T Value { get; }

    // We use only AllowNull here, because the parameter only represents
    // an input, unlike the property which has both input and output
    public Box([AllowNull] T value)
    {
        Value = value;
    }

    public static Box<T> CreateDefault()
    {
        return new Box<T>(default);
    }

    public static void UseStringDefault()
    {
        var box = Box<string>.CreateDefault();
        // Since 'box.Value' is a reference type here, [MaybeNull]
        // makes us warn on dereference of it.
        _ = box.Value.Length;
    }

    public static void UseIntDefault()
    {
        // Since 'box.Value' is a value type here, we don't warn on
        // dereference even though the original property has [MaybeNull]
        var box = Box<int>.CreateDefault();
        _ = box.Value.ToString();
    }
}

请参阅 https://devblogs.microsoft.com/dotnet/try-out-nullable-reference-types 了解更多信息,尤其是"

Please see https://devblogs.microsoft.com/dotnet/try-out-nullable-reference-types for more information, particularly the section "the issue with T?".

这篇关于可空的引用类型:如何指定"T"?类型而不限制类或结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆