I am using the Description attribute in my enums to provide a user friendly name to an enum field. e.g.
public enum InstallationType
{
[Description("Forward of Bulk Head")]
FORWARD = 0,
[Description("Rear of Bulk Head")]
REAR = 1,
[Description("Roof Mounted")]
ROOF = 2,
}
And accessing this is easy with a nice helper method:
public static string GetDescriptionFromEnumValue(Enum value)
{
DescriptionAttribute attribute = value.GetType()
.GetField(value.ToString())
.GetCustomAttributes(typeof(DescriptionAttribute), false)
.SingleOrDefault() as DescriptionAttribute;
return attribute == null ? value.ToString() : attribute.Description;
}
I need to convert this into a portable class library but it doesn't seem to have access to the System.ComponentModel library. when I try add a reverence VS tells me that I have referenced everything already.
Thanks
Since DescriptionAttribute is not available for portable class libraries you need to use another attribute. The namespace System.ComponentModel.DataAnnotations which is available for portable class libraries provides the attribute DisplayAttribute that you can use instead.
public enum InstallationType
{
[Display(Description="Forward of Bulk Head")]
FORWARD = 0,
[Display(Description="Rear of Bulk Head")]
REAR = 1,
[Display(Description="Roof Mounted")]
ROOF = 2,
}
Your method needs to be changed to
public static string GetDescriptionFromEnumValue(Enum value)
{
DisplayAttribute attribute = value.GetType()
.GetField(value.ToString())
.GetCustomAttributes(typeof(DisplayAttribute ), false)
.SingleOrDefault() as DisplayAttribute ;
return attribute == null ? value.ToString() : attribute.Description;
}
Whether something is available to a portable class library depends a bit on exactly which frameworks you selected for the library - you get the strict intersection only. However, it could well be that this attribute simply doesn't exist in one of your targeted frameworks. In which case, one option is add your own - then you know it is available. For example:
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
public class EnumDescriptionAttribute :Attribute
{
private readonly string description;
public string Description { get { return description; } }
public EnumDescriptionAttribute(string description)
{
this.description = description;
}
}
enum Foo
{
[EnumDescription("abc")]
A,
[EnumDescription("def")]
B
}
Note that I intentionally haven't included the additional serialization construtors here, because those too depend on features that are not available on all frameworks. Changing your code from using [Description] / DescriptionAttribute to [EnumDescription] / EnumDescriptionAttribute should be fairly trivial.
Try this for retrieving attribute for enum in portable libraries:
public static class EnumsHelper
{
public static T GetAttributeOfType<T>(this Enum enumVal) where T : Attribute
{
var typeInfo = enumVal.GetType().GetTypeInfo();
var v = typeInfo.DeclaredMembers.First(x => x.Name == enumVal.ToString());
return v.GetCustomAttribute<T>();
}
}
Update: also you should declare new attribute (look like DescriptionAttribute not available in PCL), for example next:
public class MyDescriptionAttribute : Attribute
{
public virtual string Text { get; set; }
}
and add one more method in EnumsHelper class:
public static class EnumsHelper
{
...
public static string GetDescription(this Enum enumVal)
{
var attr = GetAttributeOfType<MyDescriptionAttribute>(enumVal);
return attr != null ? attr.Text : string.Empty;
}
}
and if you have next enum:
public enum InstallationType
{
[MyDescription(Text = "Forward of Bulk Head")]
FORWARD = 0
}
you can retrieve description with code like this:
static void Main(string[] args)
{
var it = InstallationType.FORWARD;
var description = it.GetDescription();
Console.WriteLine(description);
}
Related
I've got an enum class...
public enum LeadStatus : byte
{
[Display(Name = "Created")] Created = 1,
[Display(Name = "Assigned")] Assigned = 2,
....
}
Name of course is out-of-the-box. From MetaData...
namespace System.ComponentModel.DataAnnotations
{
public sealed class DisplayAttribute : Attribute
{
...
public string Name { get; set; }
...
}
}
Suppose I wanted my own custom Display Attribution, such as "BackgroundColor"...
[Display(Name = "Created", BackgroundColor="green")] Created = 1
I've seen a few other threads here that kinda dance around the issue, but the context is different enough that I can't make it work. I assume I need to create some sort of extension / override class, but I am not picturing this in my head.
Thanks!
Having your own attribute.
public sealed class ExtrasDisplayAttribute : Attribute
{
public string Name { get; set; }
public string BackgroundColor { get; set; }
}
And this extension method.
namespace ExtensionsNamespace
{
public static class Extensions
{
public static TAttribute GetAttribute<TAttribute>(Enum value) where TAttribute : Attribute
{
return value.GetType()
.GetMember(value.ToString())[0]
.GetCustomAttribute<TAttribute>();
}
}
}
Now you can extract attribute from enum like this.
using static ExtensionsNamespace.Extensions;
//...
var info = GetAttribute<ExtrasDisplayAttribute>(LeadStatus.Created);
var name = info.Name;
var bg = info.BackgroundColor;
//...
public enum LeadStatus : byte
{
[ExtrasDisplay(Name = "Created", BackgroundColor = "Red")] Created = 1,
[ExtrasDisplay(Name = "Assigned")] Assigned = 2,
}
If you want to still use the original attribute you can have that too.
you should apply both attributes to single enum.
public enum LeadStatus : byte
{
[Display(Name = "Created"), ExtrasDisplay(BackgroundColor = "Red")]Created = 1,
[Display(Name = "Assigned")] Assigned = 2,
}
And extract each one you want.
var name = GetAttribute<DisplayAttribute>(LeadStatus.Created).Name;
var bg = GetAttribute<ExtrasDisplayAttribute>(LeadStatus.Created).BackgroundColor;
public sealed class DisplayAttribute : Attribute is a sealed class and therefore you cannot inherit it and add other behavior or properties to it.
Below is my assumption but someone can chime in if they know why
And you may wonder why .NET developers made it sealed? I am wondering the same and my assumption is because each of the properties in DisplayAttribute are used to inject javascript, html etc. If they left it open, and you added a BackgroundColor property to it, what does that mean? What would that do in the UI?
having concluded this this isn't possible, I went with another kind of solution. Not as tidy as I had hoped for originally, but it still gets the job done.
Methods inside enum in C#
I have a static class with constants. I am looking for options to create a method which takes a dictionary as an argument and enforcing the key to be one of the constants from the static class.Here is my static class with constants.
Here is what I am trying to do
And here is what I am trying to enforce
From the sound of it, an Enum would be more suited to what you're trying to do.
public enum MyConstants
{
FirstName,
LastName,
Title
}
public void CreateMe(Dictionary<MyConstants, string> propertyBag)
{
...
}
UPDATED
You could combine this with attributes to associate each enum with a specific string like so:
public enum PropertyNames
{
[Description("first_name")]
FirstName,
[Description("last_name")]
LastName,
[Description("title")]
Title
}
The value of each description attribute associated with each enum value could easily be grabbed via an extension method, like so:
public static class EnumExtensions
{
public static string GetDescription(this Enum value)
{
FieldInfo fieldInfo = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes =
(DescriptionAttribute[])fieldInfo.GetCustomAttributes(
typeof(DescriptionAttribute),
false);
if (attributes != null &&
attributes.Length > 0)
return attributes[0].Description;
else
return value.ToString();
}
}
Then in your "CreateMe"-method you can get the description and value of each dictionary entry by doing something similar to this:
void CreateMe(Dictionary<PropertyNames, string> propertyBag)
{
foreach (var propertyPair in propertyBag)
{
string propertyName = propertyPair.Key.GetDescription();
string propertyValue = propertyPair.Value;
}
}
Even though this has been already answered, there is another approach, like so:
public class MyOwnEnum
{
public string Value { get; private set; }
private MyOwnEnum(string value)
{
Value = value;
}
public static readonly MyOwnEnum FirstName = new MyOwnEnum("Firstname");
public static readonly MyOwnEnum LastName = new MyOwnEnum("LastName");
}
It behaves same way like Enum and can be used in your code with same syntax. I cannot give credit to whoever came up with it, but I believe I came upon it when searching for Enums with multiple values.
With strings you can't enforce fact that keys come from limited set of vialues compile time.
Use enum or custom class (possibly with implicit conversion to string) instead.
I know following syntax is possible with enum, and one can get value by parsing it in int or char.
public enum Animal { Tiger=1, Lion=2 }
public enum Animal { Tiger='T', Lion='L' }
Although following syntax is also right
public enum Anumal { Tiger="TIG", Lion="LIO"}
How do I get the value in this case? If I convert it using ToString(), I get the KEY not the VALUE.
If you really insist on using enum to do this, you can do it by having a Description attribute and getting them via Reflection.
public enum Animal
{
[Description("TIG")]
Tiger,
[Description("LIO")]
Lion
}
public static string GetEnumDescription(Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes =
(DescriptionAttribute[])fi.GetCustomAttributes(
typeof(DescriptionAttribute),
false);
if (attributes != null &&
attributes.Length > 0)
return attributes[0].Description;
else
return value.ToString();
}
Then get the value by string description = GetEnumDescription(Animal.Tiger);
Or by using extension methods:
public static class EnumExtensions
{
public static string GetEnumDescription(this Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes =
(DescriptionAttribute[])fi.GetCustomAttributes(
typeof(DescriptionAttribute),
false);
if (attributes != null &&
attributes.Length > 0)
return attributes[0].Description;
else
return value.ToString();
}
}
Then use it by string description = Animal.Lion.GetEnumDescription();
You can't use strings in enums. Use one or multiple dictionaries istead:
Dictionary<Animal, String> Deers = new Dictionary<Animal, String>
{
{ Animal.Tiger, "TIG" },
{ ... }
};
Now you can get the string by using:
Console.WriteLine(Deers[Animal.Tiger]);
If your deer numbers are in line ( No gaps and starting at zero: 0, 1, 2, 3, ....) you could also use a array:
String[] Deers = new String[] { "TIG", "LIO" };
And use it this way:
Console.WriteLine(Deers[(int)Animal.Tiger]);
Extension method
If you prefer not writing every time the code above every single time you could also use extension methods:
public static String AsString(this Animal value) => Deers.TryGetValue(value, out Animal result) ? result : null;
or if you use a simple array
public static String AsString(this Animal value)
{
Int32 index = (Int32)value;
return (index > -1 && index < Deers.Length) ? Deers[index] : null;
}
and use it this way:
Animal myAnimal = Animal.Tiger;
Console.WriteLine(myAnimal.AsString());
Other possibilities
Its also possible to do the hole stuff by using reflection, but this depends how your performance should be ( see aiapatag's answer ).
That is not possible, the value of the enum must be mapped to a numeric data type. (char is actually a number wich is wirtten as a letter)
However one solution could be to have aliases with same value such as:
public enum Anumal { Tiger=1, TIG = 1, Lion= 2, LIO=2}
Hope this helps!
This isn't possible with Enums. http://msdn.microsoft.com/de-de/library/sbbt4032(v=vs.80).aspx
You can only parse INT Values back.
I would recommend static members:
public class Animal
{
public static string Tiger="TIG";
public static string Lion="LIO";
}
I think it's easier to handle.
As DonBoitnott said in comment, that should produce compile error. I just tried and it does produce. Enum is int type actually, and since char type is subset of int you can assign 'T' to enum but you cannot assign string to enum.
If you want to print 'T' of some number instead of Tiger, you just need to cast enum to that type.
((char)Animal.Tiger).ToString()
or
((int)Animal.Tiger).ToString()
Possible alternative solution:
public enum SexCode : byte { Male = 77, Female = 70 } // ascii values
after that, you can apply this trategy in your class
class contact {
public SexCode sex {get; set;} // selected from enum
public string sexST { get {((char)sex).ToString();}} // used in code
}
I have a custom attribute that I apply to properties on a class. This attribute is used for exporting the class's properties to a flat file.
One of the attribute's properties is FieldOrder. I need to make sure the order in which I export the properties of the class is correct. Also, not all properties on the class will have the custom attribute.
I found this article: How do I sort a generic list based on a custom attribute? This solution assumes all properties have the custom attribute, which isn't my case. I was also hoping for more elegant solution.
Your help is greatly appreciated!
public interface IFileExport{}
public class ExportAttribute: Attribute
{
public int FieldOrder { get; set; }
public int FieldLength { get; set; }
public ExportAttribute() { }
}
public class ExportClass: IFileExport
{
[ExportAttribute( FieldOrder = 2, FieldLength = 25 )]
public string LastName { get; set; }
[ExportAttribute( FieldOrder=1, FieldLength=25)]
public string FirstName { get; set; }
[ExportAttribute( FieldOrder = 3, FieldLength = 3 )]
public int Age { get; set; }
public ExportClass() { }
}
public class TestClass
{
public static List<PropertyInfo> GetPropertiesSortedByFieldOrder
(IFileExport fileExport)
{
//get all properties on the IFileExport object
PropertyInfo[] allProperties = fileExport
.GetType()
.GetProperties( BindingFlags.Instance | BindingFlags.Public );
// now I need to figure out which properties have the ExportAttribute
//and sort them by the ExportAttribute.FieldOrder
}
}
UPDATE: I'm ordering the properties by ExportAttribute.FieldOrder Ascending
public static List<PropertyInfo> GetPropertiesSortedByFieldOrder( IFileExport fileExport )
{
PropertyInfo[] allProperties = GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Select(x => new
{
Property = x,
Attribute = (ExportAttribute)Attribute.GetCustomAttribute(x, typeof(ExportAttribute), true)
})
.OrderBy(x => x.Attribute != null ? x.Attribute.FieldOrder : -1)
.Select(x => x.Property)
.ToArray();
}
Since you didn't explain how you wanted properties without the attribute ordered, I have made it so that they would be at the beginning. But the gist of this code is:
Get the properties
Throw them into an anonymous type so you have easy access to both the property and the attribute.
Order by the FieldOrder, using -1 for properties without the attribute. (not sure what you wanted here)
Transform the sequence back into a sequence of PropertyInfo
Convert it into a PropertyInfo[] array.
You can use either of the following options.
First option: pass anonymous function to OrderBy
return allProperties.OrderBy(m => m.GetCustomAttribute<ExportAttribute>() == null ? -1 :
m.GetCustomAttribute<ExportAttribute>().FieldOrder).ToList();
Second option: create the function for selecting the key and pass it to OrderBy
return allProperties.OrderBy(KeySelector).ToList();
The key selector function is defined as in here:
public static int KeySelector(PropertyInfo info)
{
ExportAttribute attr = info.GetCustomAttribute<ExportAttribute>();
return attr == null ? -1 : attr.FieldOrder;
}
If the property does not have ExportAttribute, the selector will return -1. You can choose any other default value.
The second approach lets you define other types of selectors for ordering and just call the new selector you have defined.
You should be able to use the GetCustomAttributes() method on each PropertyInfo to filter the properties with the correct attributes, and then sort the remaining items.
static void Main(string[] args)
{
//get all properties on the IFileExport object
PropertyInfo[] allProperties = fileExport.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
Array.Sort(allProperties, ArrayAttributeComparison);
}
private static int ArrayAttributeComparison(PropertyInfo x, PropertyInfo y)
{
//Do null checks here
ExportAttribute xExportAttribute = GetExportAtribute(x);
ExportAttribute yExportAttribute = GetExportAtribute(x);
//Do null checks here
return xExportAttribute.FieldOrder - yExportAttribute.FieldOrder;
}
private static ExportAttribute GetExportAtribute(PropertyInfo propertyInfo)
{
object[] attributes = propertyInfo.GetCustomAttributes(true);
foreach (var t in attributes)
{
if (t is ExportAttribute)
{
return (ExportAttribute)t;
}
}
return null;
}
Whats the best approach for getting the attribute values from a classes methods and from the interface methods when the methods are overloaded?
For example I would want to know that in the following example the Get method with one parameter has the two attributes and the values are 5 and "any" while the other method has attributes with values 7 and "private".
public class ScopeAttribute : System.Attribute
{
public string Allowed { get; set; }
}
public class SizeAttribute : System.Attribute
{
public int Max { get; set; }
}
public interface Interface1
{
[SizeAttribute( Max = 5 )]
string Get( string name );
[SizeAttribute( Max = 7 )]
string Get( string name, string area );
}
public class Class1 : Interface1
{
[ScopeAttribute( Allowed = "any" )]
public string Get( string name )
{
return string.Empty;
}
[ScopeAttribute( Allowed = "private" )]
public string Get( string name, string area )
{
return string.Empty;
}
}
The only way I found was to check what interfaces the class implements and check attributes of the properties (if any exist) on those interfaces:
static bool HasAttribute (PropertyInfo property, string attribute) {
if (property == null)
return false;
if (GetCustomAttributes ().Any (a => a.GetType ().Name == attribute))
return true;
var interfaces = property.DeclaringType.GetInterfaces ();
for (int i = 0; i < interfaces.Length; i++)
if (HasAttribute (interfaces[i].GetProperty (property.Name), attribute))
return true;
return false;
}
You can probably adopt it to methods equally easy.
Note: overall approach is tested but the code itself is ad-hoc and may not compile.
You can use TypeDescriptor API
System.ComponentModel.TypeDescriptor.GetAttributes(object)
You should use reflection to get the custom attributes values
use MemberInfo.GetCustomAttributes Method to return the custom attributes attached to your member
here is a tutorial http://msdn.microsoft.com/en-us/library/aa288454(v=VS.71).aspx
EDIT: for get attributes from interface look at here