Reputation: 4146
I am building an application that makes heavy use of Enum
s for custom data. Essentially, an object is stored in the database with about 28 separate attributes. Each attribute is a two-character field that's translated from the SQL straight over to an Enum
.
Unfortunately, I need to also translate these values into two different human-readable values. One for a legend on a data table, and one for a CSS class to style an image on the web application front-end.
To do this, I've set up two custom attributes and applied them to the Enum
where necessary. For example:
Custom Attribute Interface
public interface IAttribute<T>
{
T Value { get; }
}
Example Custom Attribute
public sealed class AbbreviationAttribute: Attribute, IAttribute<string>
{
private readonly string value;
public AbbreviationAttribute(string value)
{
this.value = value;
}
public string Value
{
get { return this.value; }
}
}
Method to Retrieve Custom Attribute from Enum
public static R GetAttributeValue<T, R>(IConvertible @enum)
{
R attributeValue = default(R);
if (@enum != null)
{
FieldInfo fi = @enum.GetType().GetField(@enum.ToString());
if (fi != null)
{
T[] attributes = fi.GetCustomAttributes(typeof(T), false) as T[];
if (attributes != null && attributes.Length > 0)
{
IAttribute<R> attribute = attributes[0] as IAttribute<R>;
if (attribute != null)
{
attributeValue = attribute.Value;
}
}
}
}
return attributeValue;
}
Example Enum
Using This Pattern
public enum Download
{
[Abbreviation("check")]
[Description("Certified")]
C = 1,
[Abbreviation("no-formal")]
[Description("No formal certification")]
NF = 2,
[Abbreviation("cert-prob")]
[Description("Certified with potential problems")]
CP = 3
}
Both Abbreviation
and Description
are custom attributes that implement IAttribute<T>
. My actual Enum
has 11 possible values, and as I mentioned before it's used in 28 separate properties in my custom object. Using custom attributes seemed the best way to map this information back and forth.
Now for the question, is this the best way to accomplish this? I store the Enum
value ("C", "NF", or "CP" in the snippet above) in the database, but I need the values of the Abbreviation and Description in my code. Also, I doubt this will be the final set of custom attributes I'll need.
Before I keep moving forward with this pattern ... is it the right way to do things? I'd rather fix potential problems with this approach now than have to track back and refactor later.
Upvotes: 28
Views: 14781
Reputation: 33738
This is the same method I use. The one downside is serialization. The custom attributes values do not serialize.
I like the custom attribute method over the database method because it ties the attribute data right to the enum instead of having to use a lookup table or class, etc.
Upvotes: 16
Reputation: 22496
I'd probably build a hash table and a special type for something like this. You may have already discarded the idea for some reason or another, but here's what I would do not knowing the specifics of your application.
class SpecialType {
// include the fields and all attributes that you need to reference, ToString method for debugging, and any serialization you need
public string foo { get; set; }
public string bar { get; set; }
public ToString() { return "SpecialType with foo '" + foo + "' and bar '" + bar + "'"; }
}
Dictionary<int, SpecialType> myDict = new Dictionary<int, SpecialType> {
{ 1, new SpecialType { foo = "XA1B2", bar = "XC3D4" } },
{ 2, new SpecialType { foo = "ZA1B2", bar = "ZC3D4" } },
{ 3, new SpecialType { foo = "YA1B2", bar = "YC3D4" } },
}
Then I could easily keep ints in my other classes to save memory, find out if a particular value was valid by checking for existence in the Keys of the Dictionary, all that jazz. It would probably be a lot easier to do databinding if you're eventually going to use WPF or read/write to disk, too.
Upvotes: 2
Reputation: 9588
Can you alter the database? I think the best option would be to make a table (or tables) to house the possible values of the enums and foreign key the main objects over to it (instead of using char codes - this makes pulling it in easier and normalizes your DB). Give the table an Abbreviation
and Description
column, then pull those in and reference them by their key, and cache them if lookups are slow.
One thing that's dangerous about the attributes is that if any of those strings ever have to change, it's a complete redeploy of the app. If you make them database values, you can change them with a simple UPDATE
.
Upvotes: 1