我已经编写了一个简单的扩展方法来帮助将字符串解析为可为空的枚举类型.

public static TEnum? ParseNullableEnum<TEnum>(this string? str)
    where TEnum : Enum
{
    if (str is null)
    {
        return null;
    }

    if (!Enum.TryParse(typeof(TEnum), str, ignoreCase: true, out var source))
    {
        throw new ArgumentOutOfRangeException(nameof(str), str, null);
    }

    return (TEnum)source;
}

如您所见,返回类型为TEnum?,其中TEnumEnum.并且启用了Nullable,因此Null是有效的值.但是,我在第return null;行收到一个错误

CS0403:无法将Null转换为类型参数‘TEnum’,因为它可能是不可为Null的值类型.请考虑改用默认设置(‘TEnum’).

这是一个VS错误,还是我做错了什么?我不会转换为TEnum,输出类型为TEnum?...对吗?

推荐答案

您想要:

public static TEnum? ParseNullableEnum<TEnum>(this string? str)
    where TEnum : struct, Enum

问题在于,Enum约束可以匹配任何特定的枚举类型,也可以匹配Enum类本身.(Enum是一个奇怪的类型:它是所有枚举类型的基类型,但它本身是一个引用类型.它基本上表示一个盒装的枚举类型,即您可以编写Enum foo = condition ? ConsoleColor.Black : ConsoleKey.A;来挑选两个随机的不同的枚举类型).

换句话说,有人可以拨打:

ParseNullableEnum<Enum>("thing")

添加struct约束会强制某人实际传递特定的枚举类型,而不是Enum.

难题的另一部分是,如果泛型类型参数T没有被限制为classstruct,那么T?意味着T是"可缺省的"而不是"可空的".这意味着:

  • 如果T是引用类型,则T?允许将null赋值
  • 如果T是一个值类型,T? does not表示Nullable<T>,则表示与T相同.

这是由于编译器为引用类型和值类型实现T?的方式不同.对于值类型,T?是类型Nullable<T>的简写,但对于引用类型,T?编译为与T相同的内容,但仅对编译器警告有效.当T是引用类型时,编译器不可能发出返回类型为T的方法,但当T是值类型时,编译器不可能发出返回类型为Nullable<T>的方法.

因此,通过不将T限制为引用或值类型,您的返回类型TEnum?并不意味着Nullable<TEnum>,它只是意味着具有不同的可空警告的TEnum.通过将TEnum约束为值类型,允许编译器发出实际返回Nullable<TEnum>的方法,因此允许具有值null.

Csharp相关问答推荐

当Visual Studio处于升级管理模式时,无法安装Torch运行时

为什么使用DXGI输出复制和Direct 3D时捕获的图像数据全为零?

Elasticsearch:当我try 使用c#将嵌套对象添加到filter中时出现问题

为什么我的ASP.NET核心MVC应用程序要为HTML元素添加一些标识符?

AsNoTrackingWithIdentitySolutions()似乎不起作用?

Blazor Foreach仅渲染最后一种 colored颜色

返回TyedResults.BadRequest<;字符串>;时问题详细信息不起作用

Rider将.NET安装在哪里

当用户右键单击文本框并单击粘贴时触发什么事件?

为基本审计设置Audit.EntityFramework.Core

我如何让我的秒表保持运行场景而不重置

当索引和外键是不同的数据类型时,如何设置导航属性?

net中从位图获取坐标和绘制折线

为什么ReadOnlySpan;T&>没有Slice(...)的重载接受Range实例的?

JsonPath在Newtonsoft.Json';S实现中的赋值

WPF动态设置弹出窗口水平偏移

如何正确处置所有动态控件?

如何读取TagHelper属性的文本值?

如何在特定时间间隔运行多个后台任务?

为什么Visual Studio 2022建议IDE0251将我的方法设置为只读?