15

I'm trying to write an Extension method for nullable Enums.
Like with this example:

// ItemType is an enum
ItemType? item;
...

item.GetDescription();

So I wrote this method which doesn't compile for some reason that I don't understand:

public static string GetDescription(this Enum? theEnum)
{
    if (theEnum == null)
        return string.Empty;

    return GetDescriptionAttribute(theEnum);
}

I'm getting the following error on Enum?:

only non-nullable value type could be underlying of system.nullable

Why? Enum can not have the value null!

Update:

If have lots of enums, ItemType is just an example of one of them.

4 Answers 4

21

System.Enum is a class, so just drop the ? and this should work.

(By "this should work", I mean if you pass in a null-valued ItemType?, you'll get a null Enum in the method.)

public static string GetDescription(this Enum theEnum)
{
    if (theEnum == null)
        return string.Empty;
    return GetDescriptionAttribute(theEnum);
}
enum Test { blah }

Test? q = null;
q.GetDescription(); // => theEnum parameter is null
q = Test.blah;
q.GetDescription(); // => theEnum parameter is Test.blah
Sign up to request clarification or add additional context in comments.

10 Comments

@Jacek: I was going to write that, but I tested it and it, surprisingly, works.
Out of curiosity, does this mean that theEnum is boxed to send here? Or in general, any method which takes an Enum as a parameter boxes the input? EDIT: Just whipped up a quick test and checked the IL and yup, it does.
Weird thing: it works with Nullable<ItemType> as well, but I'm not getting intellisense with it.
@gdoron I get Intellisense with both Test? and Nullable<Test> in my case. (VS2010)
|
4

You can simply make your extension method generic:

public static string GetDescription<T>(this T? theEnum) where T : struct
{ 
    if (!typeof(T).IsEnum)
        throw new Exception("Must be an enum.");

    if (theEnum == null) 
        return string.Empty; 
 
    return GetDescriptionAttribute(theEnum); 
}

Unfortunately, you cannot use System.Enum in a generic constraint, so the extension method will show for all nullable values (hence the extra check).

EDIT: C# 7.3 introduced new generic constraints which now allow restricting a generic argument to an enum, like so:

public static string GetDescription<T>(this T? theEnum) where T : Enum
{ 
    if (theEnum == null) 
        return string.Empty; 
 
    return GetDescriptionAttribute(theEnum); 
}

Thanks @JeppeStigNielsen for pointing that out.

2 Comments

This is nice because it avoids boxing. You can also say !theEnum.HasValue if you prefer. If anyone is interested in generic constraint to System.Enum, also read Generic constraints for enums and delegates.
@LenielMaccaferri That 2009 blog post can now be seen here. The above answer, and my comment, was from 2012. However, all this is now mostly obsolete because since C# 7.3 (from 2018) you can use where T : struct, Enum and that will guarantee that T is a value type with base class System.Enum.
3

You should use the actual enum type in your method signature:

public static string GetDescription(this ItemType? theEnum)

System.ValueType and System.Enum are not treated as value types (only types derived from them), so they are nullable (and you don't to specify them as nullable). Try it:

// No errors!
ValueType v = null;
Enum e = null;

You could also try this signature:

public static string GetDescription<T>(this T? theEnum) where T: struct

This also allows structs though, which might not be what you want. I think i remember some library that adds a type constraint of enum after compilation (C# doesn't allow it) though. Just need to find it...

EDIT: Found it:

http://code.google.com/p/unconstrained-melody/

3 Comments

If have lots of enums, ItemType is just an example. I was sure it's obvious, sorry.
Ohh, the second part you added answers my question, thanks. But is there a way to overcome this weird design?
You can use a generic constraint, but C# doesn't allow specifying enum as a constraint. See my edit for a solution.
0

Maybe better is add extra value to your enum and call it null :)

3 Comments

Yeah, I agree, an Enum with one of its values "Undefined" or "Null" or something would make more sense. Or you could wrap your enum in a class and make that null if you really wanted a null value.
Huh? The exact opposite is true - only value types can be used with Nullable<T>. And how is INullable relevant?
The enum null isn't option. not in asp.net-MVC

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.