Reputation: 918
I have defined the following enum
:
public enum DeviceType
{
[Description("Set Top Box")]
Stb = 1,
Panel = 2,
Monitor = 3,
[Description("Wireless Keyboard")]
WirelessKeyboard = 4
}
I'm utilising the Description
attribute to allow me to pull out a more user-readable version of the enum to display in the UI. I get the description using the following code:
var fieldInfo = DeviceType.Stb.GetType().GetField(DeviceType.Stb.ToString());
var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
var description = (attributes.Length > 0 ? attributes[0].Description : DeviceType.Stb.ToString());
The above code will give me: description = "Set Top Box"
. If there is no Description
attribute set, it will give me the string value of the enum.
I now want to add a second/custom attribute to each of the enums (called 'Value' for examples sake). eg:
public enum DeviceType
{
[Description("Set Top Box")]
[Value("19.95")]
Stb = 1,
[Value("99")]
Panel = 2,
[Value("199.99")]
Monitor = 3,
[Description("Wireless Keyboard")]
[Value("20")]
WirelessKeyboard = 4
}
I will need to pull out the new Value
attribute much the same way I currently do with the Description
attribute.
Is it possible to extend the existing Description
attribute to somehow include the new Value
attribute, or is it best to create the new attribute separately?
Upvotes: 23
Views: 16765
Reputation: 30803
why not doing it in one class. It is a bit more work in the beginning but:
Simple()
)"{Binding namespace:DeviceType.All}"
and "{Binding SomeDeviceTypeProperty.Value}"
var invalid = (DeviceType)100;
example code
public class DeviceType
{
public static readonly DeviceType
Stb = new DeviceType("Stb", "Set Top Box", 19.95),
Panel = new DeviceType("Panel", 99),
Monitor = new DeviceType("Monitor", 19.95),
Cable = Simple("Cable"),
Connector = Simple("Connector"),
WirelessKeyboard = new DeviceType("WirelessKeyboard", "Wireless Keyboard", 20);
private static readonly IEnumerable<DeviceType> _all = typeof(DeviceType)
.GetFields(BindingFlags.Public | BindingFlags.Static).Select(f => (DeviceType)f.GetValue(null)).ToArray();
public static IEnumerable<DeviceType> All { get { return _all; } }
public static DeviceType Parse(string name)
{
foreach (var item in All)
{
if (item.Name == name)
return item;
}
throw new KeyNotFoundException(name);
}
private static DeviceType Simple(string name)
{
return new DeviceType(name, name, 9.95);
}
private DeviceType(string name, decimal value) : this(name, name, value) { }
private DeviceType(string name, string description, decimal value)
{
Name = name;
Description = description;
Value = value;
}
public string Name { get; private set; }
public string Description { get; private set; }
public decimal Value { get; private set; }
public override string ToString()
{
return Name;
}
}
Upvotes: 3
Reputation: 15284
Create a new attribute seperately called DeviceInformation...
[AttributeUsage(AttributeTargets.All)]
public class DeviceInformationAttribute : DescriptionAttribute
{
public DeviceInformationAttribute(string description, string value)
{
this.Description = description;
this.Value = value;
}
public string Description { get; set; }
public string Value { get; set; }
}
You can also use the extension method to retrieve the value of any attribute
static void Main(string[] args)
{
var info = DeviceType.Stb.GetAttribute<DeviceInformationAttribute>();
Console.WriteLine("Description: {0}\nValue:{1}",info.Description, info.Value);
}
public static class Extensions
{
public static TAttribute GetAttribute<TAttribute>(this Enum enumValue)
where TAttribute : Attribute
{
return enumValue.GetType()
.GetMember(enumValue.ToString())
.First()
.GetCustomAttribute<TAttribute>();
}
}
public enum DeviceType
{
[DeviceInformation("foobar", "100")]
Stb = 1,
}
In response to the comment
@Aydin Adn I do love the use of the extension method, very nice! Do you have a solution for the case of DeviceType.Panel which does not have a description, but needs the Value attribute? (see comments on Patrick's answer)
[AttributeUsage(AttributeTargets.All)]
public class DeviceInformationAttribute : Attribute
{
public DeviceInformationAttribute(string description)
{
this.Description = description;
}
public DeviceInformationAttribute(decimal value)
{
this.Description = string.Empty;
this.Value = value;
}
public DeviceInformationAttribute(string description, decimal value)
{
this.Description = description;
this.Value = value;
}
public string Description { get; set; }
public decimal Value { get; set; }
}
Upvotes: 22
Reputation: 33
What you want to do is: Create an Attribute to describe the enume more specific: This is how you can do it:
public class EnumValue : Attribute
{
public Decimal Value { get; private set; }
public EnumValue(Decimal value)
{
this.Value = value;
}
}
This can be used through this Extension Method:
private static Decimal GetEnumCustomAttribute(this Enum leEnum, Typ typ)
{
try
{
if (leEnum == null) throw new ArgumentNullException("leEnum");
Type type = leEnum.GetType();
MemberInfo[] memInfo = type.GetMember(leEnum.ToString());
if (memInfo != null && memInfo.Length > 0)
{
object[] attrs = memInfo[0].GetCustomAttributes(typeof(EnumValue), false);
if (attrs != null && attrs.Length > 0)
return ((EnumValue)attrs[0]).Value;
}
return Decimal.MinValue;
}
catch (Exception)
{
throw;
}
}
Give it a try!
Upvotes: 1
Reputation: 156928
Yes, that is fairly easy to do. Just derive the existing DescriptionAttribute
class:
[AttributeUsageAttribute(AttributeTargets.All)]
public class DescriptionWithValueAttribute : DescriptionAttribute
{
public DescriptionWithValueAttribute(string description, string value) : base(description)
{
this.Value = value;
}
public string Value { get; private set; }
}
Then you can use it like this:
public enum DeviceType
{
[DescriptionWithValue("Set Top Box", "19.95")]
Stb = 1,
}
Your code to retrieve the attributes will remain almost the same, just replace the type names.
Upvotes: 13