Shaiju T
Shaiju T

Reputation: 6609

Why Enum.TryParse requires constraint where T : struct

I was trying understand a extension method to convert string to Enum found here.

public static T ToEnum<T>(this string value, T defaultValue)
{
     if (string.IsNullOrEmpty(value))
     {
        return defaultValue;
     }

     T result;
     return Enum.TryParse<T>(value, true, out result) ? result : defaultValue;
}

Compile Error:

The type 'T' must be a non-nullable value type in order to use it as parameter 'TEnum' in the generic type or method 'Enum.TryParse(string, bool, out TEnum)'

One the Comments says to add where T : struct for the extension method to work.

Method With Constraint:

public static T ToEnum<T>(this string value, T defaultValue) where T : struct
{
    if (string.IsNullOrEmpty(value))
    {
          return defaultValue;
    }

    T result;
    return Enum.TryParse<T>(value, true, out result) ? result : defaultValue;
}

I read the docs on Enum.TryParse , but I don't understand in docs on why where T : struct is added as constraint for type T ?

Why would above extension wont work without constraint as struct why not other value types ? How to relate struct and Enum type ? or Is it just a syntax to follow ?

Update:

Most of them said any value type can be used , I tried to use where T : int But I get compile time error:

'int' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.

Upvotes: 2

Views: 1255

Answers (2)

MakePeaceGreatAgain
MakePeaceGreatAgain

Reputation: 37000

The constraint struct does not only include types you declared via struct MyStruct, but also many built-in-types such as int, byte or char. Actually the constraint restricts T to be of any value-type, see this from the C#-specification 9.4.5 Satisfying constraints:

If the constraint is the value type constraint (struct), the type A shall satisfy one of the following

  • A is a struct type or enum type, but not a nullable value type. [Note: System.ValueType and System.Enum are reference types that do not satisfy this constraint. end note]
  • A is a type parameter having the value type constraint (§15.2.5)

Of course it´ll be nice if there were a more restricitve constraint.

As of your edit: your compiler-message is pretty clear in this case. When using a type as constraint, you can use only interfaces or non-sealed classed. Restricting a generic type-parameter to match exactly one single class (or struct) would make a generic quite useless, wouldn´t it? Restricting your generic to int will effectivly turn your method-signature in something like this:

public static int ToEnum(this string value, int defaultValue)

because there´s only one struct matching the constraint.

Upvotes: 1

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726579

This is done to enable partial error checking at compile time:

  • Reference types are rejected at compile time,
  • Value types that are not enums are rejected at runtime.

It would be better if you could write where T : Enum, but C# compiler prohibits this:

A constraint cannot be special class `System.Enum'

For more information on this error see this Q&A. In particular, see this answer for a short work-around to the problem.

Upvotes: 0

Related Questions