Получение значения пользовательских атрибутов перечислимого


Предположим, у нас есть перечислимый под названием "Планета" и настраиваемого атрибута класса "PlanetAttr", эти методы дадут вам значение атрибута для данной планеты значение:

private static PlanetAttr GetAttr(Planet p)
{
    return (PlanetAttr)Attribute.GetCustomAttribute(ForValue(p), typeof(PlanetAttr));
}

private static MemberInfo ForValue(Planet p)
{
    return typeof(Planet).GetField(Enum.GetName(typeof(Planet), p));
}

Но это хороший способ, чтобы получить значение пользовательского атрибута от перечислимый? Мне неудобно с количеством участвующих вызовы метода. Существует ли более эффективный способ, например, это можно сделать не глядя на имя перечислимой константы?

Этот код на сайте StackOverflow вопрос.

using System;
using System.Reflection;

class PlanetAttr: Attribute
{
    internal PlanetAttr(double mass, double radius)
    {
        this.Mass = mass;
        this.Radius = radius;
    }
    public double Mass { get; private set; }
    public double Radius { get; private set; }
}

public static class Planets
{
    public static double GetSurfaceGravity(this Planet p)
    {
        PlanetAttr attr = GetAttr(p);
        return G * attr.Mass / (attr.Radius * attr.Radius);
    }

    public static double GetSurfaceWeight(this Planet p, double otherMass)
    {
        return otherMass * p.GetSurfaceGravity();
    }

    public const double G = 6.67300E-11;

    private static PlanetAttr GetAttr(Planet p)
    {
        return (PlanetAttr)Attribute.GetCustomAttribute(ForValue(p), typeof(PlanetAttr));
    }

    private static MemberInfo ForValue(Planet p)
    {
        return typeof(Planet).GetField(Enum.GetName(typeof(Planet), p));
    }

}

public enum Planet
{
    [PlanetAttr(3.303e+23, 2.4397e6)]  MERCURY,
    [PlanetAttr(4.869e+24, 6.0518e6)]  VENUS,
    [PlanetAttr(5.976e+24, 6.37814e6)] EARTH,
    [PlanetAttr(6.421e+23, 3.3972e6)]  MARS,
    [PlanetAttr(1.9e+27,   7.1492e7)]  JUPITER,
    [PlanetAttr(5.688e+26, 6.0268e7)]  SATURN,
    [PlanetAttr(8.686e+25, 2.5559e7)]  URANUS,
    [PlanetAttr(1.024e+26, 2.4746e7)]  NEPTUNE,
    [PlanetAttr(1.27e+22,  1.137e6)]   PLUTO
}


57726
39
задан 13 октября 2011 в 09:10 Источник Поделиться
Комментарии
1 ответ

Сделать это общего назначения с помощью дженериков.

Хотя я бы настоятельно рекомендуем Вам переименовать ваш атрибут для подражания .Чистая руководящие принципы. Он всегда должен быть в виде Имя_атрибутаатрибута. Enum-значений должны быть в верблюжьего. И это общее для имен классов, содержащих методы расширения должны быть названы так же, как класс это расширение сопровождается расширениями.

В противном случае, это довольно много, как вы бы получить пользовательские атрибуты поля.

public static class EnumExtensions
{
public static TAttribute GetAttribute<TAttribute>(this Enum value)
where TAttribute : Attribute
{
var type = value.GetType();
var name = Enum.GetName(type, value);
return type.GetField(name) // I prefer to get attributes this way
.GetCustomAttributes(false)
.OfType<TAttribute>()
.SingleOrDefault();
}
}

public class PlanetInfoAttribute : Attribute
{
internal PlanetInfoAttribute(double mass, double radius)
{
this.Mass = mass;
this.Radius = radius;
}
public double Mass { get; private set; }
public double Radius { get; private set; }
}

public enum Planet
{
[PlanetInfo(3.303e+23, 2.43970e6)] Mecury,
[PlanetInfo(4.869e+24, 6.05180e6)] Venus,
[PlanetInfo(5.976e+24, 6.37814e6)] Earth,
[PlanetInfo(6.421e+23, 3.39720e6)] Mars,
[PlanetInfo(1.900e+27, 7.14920e7)] Jupiter,
[PlanetInfo(5.688e+26, 6.02680e7)] Saturn,
[PlanetInfo(8.686e+25, 2.55590e7)] Uranus,
[PlanetInfo(1.024e+26, 2.47460e7)] Neptune,
[PlanetInfo(1.270e+22, 1.13700e6)] Pluto,
}

public static class PlanetExtensions
{
public static double GetSurfaceGravity(this Planet p)
{
var attr = p.GetAttribute<PlanetInfoAttribute>();
return G * attr.Mass / (attr.Radius * attr.Radius);
}

public static double GetSurfaceWeight(this Planet p, double otherMass)
{
return otherMass * p.GetSurfaceGravity();
}

public const double G = 6.67300E-11;
}


Следует отметить, что есть методы, чтобы получить пользовательские атрибуты в рамках сегодня .Нетто 4.5. Увидеть CustomAttributeExtensions класс. Это должно упростить метод расширения немного. Может быть, стоит изменить название расширения для GetCustomAttribute() , так как он всегда будет настраиваемого атрибута.

public static class EnumExtensions
{
public static TAttribute GetAttribute<TAttribute>(this Enum value)
where TAttribute : Attribute
{
var type = value.GetType();
var name = Enum.GetName(type, value);
return type.GetField(name) // I prefer to get attributes this way
.GetCustomAttribute<TAttribute>();
}
}

54
ответ дан 13 октября 2011 в 11:10 Источник Поделиться