Simulate properties for Enumerations in the .NET Framework 3.5
I am sure that many periodically encountered the need to specify any simple properties for enumeration elements in C #.
There are various ways to solve this problem, the most popular of which, in my opinion, is to write an auxiliary static method that takes an enumeration as a parameter and returns the result of the desired type.
I want to offer you a slightly different, more universal and elegant way, based on attributes, methods of expansion and reflection.
Take a look at how clearly we can describe attributes for enumeration elements:
... and how simple we can get the values of these elements:
Let's create an abstract BaseAttribute class , from which our own attributes will be inherited in the future. The constructor accepts and places the object for storage. The GetValue () method returns a stored object.
Next, we need to create an extension method, which for the element of any enumeration will return the value of the required attribute. To do this, create a static class EnumAttributesBaseLogic and define our method in it, which we will call GetAttributeValue . The last argument to the method is the value that will be returned if the passed enumeration element is not marked with the passed attribute.
That's all! Now we can create the attributes we need in just one line. Take a look at how to simply create the Weight * attribute :
* Remember that only constants or arrays of primitive types can be used as attribute arguments .
Also, we can simply now create an extension method to read the value of the attribute we just created:
For convenience, I recommend putting your own attribute definitions and a static class with advanced methods for reading attributes into a separate file:
A working example can be downloaded from here:
http://www.googman.ru/sources/enumattributesdemo.zip (9.1 kb)
PS Do not judge strictly - my first post.
There are various ways to solve this problem, the most popular of which, in my opinion, is to write an auxiliary static method that takes an enumeration as a parameter and returns the result of the desired type.
I want to offer you a slightly different, more universal and elegant way, based on attributes, methods of expansion and reflection.
Attributes provide an efficient method for associating declarative information with C # code (types, methods, properties, etc.). An attribute associated with a program entity can be requested at runtime using a method called reflection.
© MSDN, http://msdn.microsoft.com/en-us/library/z0w1kczw.aspx
Reflection (reflection) is used to dynamically create a type instance, bind a type to an existing object, as well as obtain a type from an existing object and dynamically call it methods or access to its fields and properties.
© MSDN, http://msdn.microsoft.com/en-us/library/ms173183.aspx
Extension Methodsallow you to “add” methods to existing types without creating a new derived type, recompiling, or otherwise changing the original type. Extension methods are a special kind of static method, but they are invoked as if they were instance methods in an extended type.
© MSDN, http://msdn.microsoft.com/en-us/library/bb383977.aspx
Take a look at how clearly we can describe attributes for enumeration elements:
public enum Womans
{
[Age(25)]
[Weight(54.5)]
Masha,
[Age(32)]
[Weight(102.5)]
Lena,
[Age(44)]
[Weight(77.4)]
Ira,
[Age(28)]
[Weight(63.75)]
Fekla
}
public enum Status
{
[RussianName("Открыт")]
Opened = 100,
[RussianName("Закрыт")]
Closed = 200,
[RussianName("Что-то еще")]
AnythingElse = 500
}
... and how simple we can get the values of these elements:
double iraWeight = Womans.Ira.GetWeight();
int lenaAge = Womans.Lena.GetAge();
string closedName = Status.Closed.GetRussianName();
Implementation
Let's create an abstract BaseAttribute class , from which our own attributes will be inherited in the future. The constructor accepts and places the object for storage. The GetValue () method returns a stored object.
public abstract class BaseAttribute : Attribute
{
private readonly object _value;
public BaseAttribute(object value) { this._value = value; }
public object GetValue() { return this._value; }
}
Next, we need to create an extension method, which for the element of any enumeration will return the value of the required attribute. To do this, create a static class EnumAttributesBaseLogic and define our method in it, which we will call GetAttributeValue . The last argument to the method is the value that will be returned if the passed enumeration element is not marked with the passed attribute.
public static class EnumAttributesBaseLogic
{
public static VAL GetAttributeValue(this ENUM enumItem, Type attributeType, VAL defaultValue)
{
var attribute = enumItem.GetType().GetField(enumItem.ToString()).GetCustomAttributes(attributeType, true)
.Where(a => a is BaseAttribute)
.Select(a => (BaseAttribute)a)
.FirstOrDefault();
return attribute == null ? defaultValue : (VAL)attribute.GetValue();
}
}
That's all! Now we can create the attributes we need in just one line. Take a look at how to simply create the Weight * attribute :
public class Weight : BaseAttribute { public Weight(double value) : base(value) { } }
* Remember that only constants or arrays of primitive types can be used as attribute arguments .
Also, we can simply now create an extension method to read the value of the attribute we just created:
public static double GetWeight(this Enum enumItem)
{
return enumItem.GetAttributeValue(typeof(Weight), 0m);
}
For convenience, I recommend putting your own attribute definitions and a static class with advanced methods for reading attributes into a separate file:
using System;
namespace EnumAttributesDemo
{
public class Age : BaseAttribute { public Age(int value) : base(value) { } }
public class Weight : BaseAttribute { public Weight(double value) : base(value) { } }
public class RussianName : BaseAttribute { public RussianName(string value) : base(value) { } }
public static class EnumExtensionMethods
{
public static int GetAge(this Womans enumItem)
{
return enumItem.GetAttributeValue(typeof(Age), 0);
}
public static double GetWeight(this Womans enumItem)
{
return enumItem.GetAttributeValue(typeof(Weight), 0d);
}
public static string GetRussianName(this Status enumItem)
{
return enumItem.GetAttributeValue(typeof(RussianName), string.Empty);
}
}
}
A working example can be downloaded from here:
http://www.googman.ru/sources/enumattributesdemo.zip (9.1 kb)
PS Do not judge strictly - my first post.