0

I am trying to implement this helper function in C# 7.3:

public static T? ToEnum<T>(this string enumName)
    where T : Enum 
    => Enum.TryParse<T>(enumName, out T val) ? val : null;

But got a compiler error:

Error CS8370 Feature 'nullable reference types' is not available in C# 7.3

Why does the compiler think I am using a nullable reference type while T is constrained to be an Enum which is a value type already?

Xiaoguo Ge
  • 2,177
  • 20
  • 26
  • Enums are not reference types so the question you're asking doesn't apply. You just need to add the constraint `where T: struct`. This has been the case for over a decade – Aluan Haddad May 14 '22 at 05:03
  • 1
    While enums themselves are value types, `Enum` is a class and that's what you're using in your constraint, so that's presumably the issue. – user18387401 May 14 '22 at 05:07
  • 2
    Possible duplicate: [Why doesn't return default(T?) give a null when T is constrained to enum?](https://stackoverflow.com/questions/72170047/why-doesnt-return-defaultt-give-a-null-when-t-is-constrained-to-enum) – Yong Shun May 14 '22 at 05:13
  • Any reason `System.Enum` has to be a class instead of a struct? @user18387401 – Xiaoguo Ge May 14 '22 at 07:47
  • 1
    @XiaoguoGe Because [nearly everything is an Object](https://stackoverflow.com/a/436218/8967612). See also [this great answer](https://stackoverflow.com/a/1682604/8967612) by Eric Lippert for more details. – 41686d6564 stands w. Palestine May 16 '22 at 07:50

1 Answers1

3

This problem is not specific to nullable enums. Even if you use a non-nullable enum, it won't work. That's because while specific enum types are value types, System.Enum is a reference type as explained here. So, you need to add a struct constraint in addition to the Enum constraint.

The following should work:

public static T? ToEnum<T>(this string enumName) 
    where T : struct, Enum
    => Enum.TryParse<T>(enumName, out T val) ? val : default(T?);

Also, note that you can't use null in the second branch of the ternary operator because the compiler can't infer the type. Use default(T?) instead.

Example of usage:

enum MyEnum { a, b, c }

static void Main(string[] args)
{
    var e1 = "b".ToEnum<MyEnum>();
    var e2 = "d".ToEnum<MyEnum>();

    Console.WriteLine("e1 = " + (e1?.ToString() ?? "NULL"));  // e1 = b
    Console.WriteLine("e2 = " + (e2?.ToString() ?? "NULL"));  // e2 = NULL
}