6

I've seen examples of generic extension methods in C# for enumerations that use where T: struct, also another that uses where T: IComparable. For example, in the former case:

public static class EnumExtensionMethods
{
  public static string Description<T>(this T enumValue) where T : struct
  {
    // ...
  }
}

I'm confused why the constraint requires that type T must be a struct. I'd expect it to be where T : Enum. Can someone explain this to me? As a bonus item, maybe also explain why IComparable is also used in some examples.

FWIW, I did my research on this. I can find explanations on why IComparable is used, for example in this question, but it doesn't seem conclusive, nor do they explain why struct is used in conjunction.

void.pointer
  • 24,859
  • 31
  • 132
  • 243
  • 3
    The `Enum` generic constraint wasn't added until C# 7.3, so I'd expect generic methods written before that feature to use `struct` – Jonathon Chase Jan 24 '20 at 15:06
  • Note: "As a bonus item, maybe also explain why IComparable is also used in some examples." Stack Overflow posts ideally deal with just a single question. If still you want an answer to that part, I'd suggest creating another post - and cite some examples, otherwise we're in the dark. (There are plenty of `IComparable` implementations that *aren't* enums, for example.) – Jon Skeet Jan 24 '20 at 16:39

2 Answers2

19

I suspect you're looking at some code that was written before C# 7.3 - the ability to constrain a generic type parameter using Enum or Delegate was only introduced in C# 7.3.

But for extension methods targeting enums, you'd want both Enum and struct in the constraint, e.g.

public static string GetDescription<T>(this T enumValue) where T : struct, Enum
{
    // ...
}

That way it can only be called on concrete enum types, rather than GetDescription<Enum>(null).

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thanks, this helps, but what I'm really looking for is to understand semantically why an enum is related to a `struct`. I come from C++ primarily so maybe it's something idiomatic to C# I am missing. Can you explain this at the type level? Why does `T` have to be a `struct`? EDIT: Maybe the answer lies in your last sentence, but I don't understand it yet. – void.pointer Jan 24 '20 at 16:16
  • 4
    @void.pointer: Sorry, I assume you already understood enums at a C# level, separately from generics. Enums are always value types (although the System.Enum type is not). The `struct` constraint ensures that the type argument is a value type; the combined `where T : struct, Enum` constraint ensures that it's "a value type derived from System.Enum" - basically "that it's a specific enum type". – Jon Skeet Jan 24 '20 at 16:38
  • Thanks @JonSkeet, that helps a ton. – void.pointer Jan 24 '20 at 18:47
2

The ability to constrain a method to Enum is relatively new in C#. Using struct was a way to at least not allow reference types to be used.

germi
  • 4,628
  • 1
  • 21
  • 38