Andrus
Andrus

Reputation: 27945

How to add non generic method to wrap generic method

ASP.NET MVC4 razor helper cannot pass type parameters to generic methods. To fix this, probably best way is to add non-generic get method with signature

public static string Get(Type entityType)

How to add this wrapper so it calls generic Get method in this class. Should reflection used or is there better way?

 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
  public sealed class LocalizableDisplayNameAttributeI :   DisplayNameAttribute
   {

    public LocalizableDisplayNameAttributeI(string displayName) : base(displayName) { }

    public override string DisplayName
    {
        get
        {
            return global::Res.Translate(base.DisplayName);
        }
    }

    public static string Get<TEntity>()
    {
        foreach (LocalizableDisplayNameAttributeI attrib in
            typeof(TEntity).GetCustomAttributes(typeof(LocalizableDisplayNameAttributeI), true))
        {
            return attrib.DisplayName;
        }
        return typeof(TEntity).Name;
}}

Upvotes: 0

Views: 299

Answers (3)

Alex
Alex

Reputation: 13224

You can do that using reflection as @JeppeStigNielsen already indicated.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class LocalizableDisplayNameAttributeI : DisplayNameAttribute
{
    private static readonly MethodInfo _getMethod = typeof(LocalizableDisplayNameAttributeI)
        .GetMethods().First(x => x.IsGenericMethod && x.Name == "Get");

    public LocalizableDisplayNameAttributeI(string displayName) : base(displayName) { }

    public override string DisplayName
    {
        get
        {
            return global::Res.Translate(base.DisplayName);
        }
    }

    public static string Get(Type entityType)
    {
        return (string)_getMethod.MakeGenericMethod(entityType).Invoke(null, null);
    }

    public static string Get<TEntity>()
    {
        var attrib = typeof(TEntity)
            .GetCustomAttributes(typeof(LocalizableDisplayNameAttributeI), true)
            .FirstOrDefault() as LocalizableDisplayNameAttributeI;
        return attrib != null ? attrib.DisplayName : typeof(TEntity).Name;
    }
}

But it seems you don't really need this, because you are not using the template argument.

You can simply do:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class LocalizableDisplayNameAttributeI : DisplayNameAttribute
{
    public LocalizableDisplayNameAttributeI(string displayName) : base(displayName) { }

    public override string DisplayName
    {
        get
        {
            return global::Res.Translate(base.DisplayName);
        }
    }

    public static string Get(Type entityType)
    {
        var attrib = entityType
            .GetCustomAttributes(typeof(LocalizableDisplayNameAttributeI), true)
            .FirstOrDefault() as LocalizableDisplayNameAttributeI;
        return attrib != null ? attrib.DisplayName : entityType.Name;
    }

    public static string Get<TEntity>()
    {
        return Get(typeof(TEntity));
    }
}

Upvotes: 1

BJ Myers
BJ Myers

Reputation: 6813

Going from a Type to a generic call is a pain, but going from a generic call to a Type is easy. Can you swap your wrapper order?

public static string Get<TEntity>()
{
    return Get(typeof(TEntity));
}

public static string Get(Type entityType)
{
    foreach (LocalizableDisplayNameAttributeI attrib in
        entityType.GetCustomAttributes(typeof(LocalizableDisplayNameAttributeI), true))
    {
        return attrib.DisplayName;
    }
    return entityType.Name;
}

Upvotes: 1

Jeppe Stig Nielsen
Jeppe Stig Nielsen

Reputation: 61972

Reflection.

return (string)(
    typeof(LocalizableDisplayNameAttributeI)
    .GetMethod("Get")
    .MakeGenericMethod(entityType)
    .Invoke(null, null)
    );

This answer only relates to how to call a generic method. However in the actual case, it is much easier to just write the method again in a non-generic version. Because you only use TEntity in the context typeof(TEntity). Therefore you could simply search-and-replace typeof(TEntity) by entityType to get your non-generic version of the method.

Upvotes: 1

Related Questions