diegosasw
diegosasw

Reputation: 15654

Unable to use Enum extension method with generic

I know generics are done at compiled time, but I am getting confused with the way generics work (and I though I knew generics..).

I have created the following extension method:

public static class EnumExt
{
    /// <summary>
    /// Gets the description, if any, or the name of the enum as a string in a enum type
    /// </summary>
    public static string GetDescription<T>(this T enumType) where T : struct, IConvertible
    {
        FieldInfo fieldInfo = enumType.GetType().GetField(enumType.ToString());
        DescriptionAttribute[] descriptionAttributes = (DescriptionAttribute[])
            fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
        if (descriptionAttributes.Length > 0)
        {
            return descriptionAttributes[0].Description;
        }
        return enumType.ToString();
    }
}

I have as an example the following enum

namespace MyProject.Model
{
    [Flags]
    public enum MyEnumType
    {
        [Description("None")]
        None = 0,
        [Description("Show Products (default)")]
        Products  = 1,
        [Description("Show Tariffs")]
        Tariffs = 2
    }
}

And now I'd like to use it from an HttpHelper in MVC that returns a string (html text) like this one. Please note My class has access to my EnumExt methods.

    public static IHtmlString CheckBoxesForEnumModel<TModel>(this HtmlHelper<TModel> htmlHelper)
    {
        if (!typeof(TModel).IsEnum)
        {
            throw new ArgumentException("this helper can only be used with enums");
        }
        TModel[] allEnumValues = (TModel[])Enum.GetValues(typeof(TModel));
        foreach (TModel item in allEnumValues)
        {
            var descErr = item.GetDescription(); //does not compile, but I know it's a MyEnumType.Tariffs..
            var descOk = MyEnumType.Tariffs.GetDescription(); //this line works
            //descOk = "Show Tariffs"
        }

        return new HtmlString("ideally this is some html checkboxes with each enum description");
    }

I know I can get all the Enum values and iterate through them using the TModel like this:

TModel[] allEnumValues = (TModel[])Enum.GetValues(typeof(TModel));

but if I know a TModel is an enum (it's a MyEnumType), why can't I use it to access the enum extension method like:

allValues[0].GetDescription<>(); //ERROR. this does not compile

I guess it's because somehow I must cast it to a specific type like MyEnumType, but how to do so and keep it generic?

Thanks in advance!

UPDATE: Thanks to the first answers I was able to compile by restricting TModel to struct, IConvertible

Upvotes: 4

Views: 429

Answers (3)

nawfal
nawfal

Reputation: 73233

You need a constraint for your method. Do,

public static IHtmlString CheckBoxesForEnumModel<TModel>(this HtmlHelper<TModel> htmlHelper) where TModel : struct, IConvertible
{
   if (!typeof(TModel).IsEnum)
   {
      throw new ArgumentException("this helper can only be used with enums");
   }

   //Here some code to get all the values and the names for this Enum        
   //But HOW?? 

   return new HtmlString("ideally this is some html checkboxes with each enum description");
}

I hope the reason is obvious.

Upvotes: 2

IPValverde
IPValverde

Reputation: 2029

You created an extension method for your enum based on T where T is struct an implements IConvertible.

But in your HtmlHelper extension method your TModel does not have the same constraints, so there is not way that compiler can associate your enum extension method based on a type that is a struct and IConvertible with your TModel which is just a type.

Adding the same constraints to your HtmlHelper method will do the trick:

public static IHtmlString CheckBoxesForEnumModel<TModel>(this HtmlHelper<TModel> htmlHelper) where TModel : struct, IConvertible
{
    string description = htmlHelper.ViewData.Model.GetDescription();
}

Upvotes: 1

Nick Hill
Nick Hill

Reputation: 4917

Because your extension method is defined for T where T : struct, IConvertible.

But TModel in CheckBoxesForEnumModel doesn't conform to these generic type constraints.

You should change the signature from

public static IHtmlString CheckBoxesForEnumModel<TModel>(this HtmlHelper<TModel> htmlHelper)

to

public static IHtmlString CheckBoxesForEnumModel<TModel>(this HtmlHelper<TModel> htmlHelper)
    where TModel : struct, IConvertible

or more restrictive.

Upvotes: 3

Related Questions