Using localized enum as DataSource - c#

I've lots of enums in my app. Most of them are used on combos like this:
Enum.GetValues(typeof(TipoControlador))
Now I'd like to localize them like this: Localizing enum descriptions attributes
How can I combine them? My first thought was to override the ToString method with an extension method, but that's not possible =(

Using the other article as a basis, you can create an extension method like this:
public static class LocalizedEnumExtensions
{
private static ResourceManager _resources = new ResourceManager("MyClass.myResources",
System.Reflection.Assembly.GetExecutingAssembly());
public static IEnumerable<string> GetLocalizedNames(this IEnumerable enumValues)
{
foreach(var e in enumValues)
{
string localizedDescription = _resources.GetString(String.Format("{0}.{1}", e.GetType(), e));
if(String.IsNullOrEmpty(localizedDescription))
{
yield return e.ToString();
}
else
{
yield return localizedDescription;
}
}
}
}
You would use it like this:
Enum.GetValues(typeof(TipoControlador)).GetLocalizedNames();
Technically, this extension method will accept any array, and you can't restrict it to only work on an enum, but you could add extra validation inside the extension method if you feel it's important:
if(!e.GetType().IsEnum) throw new InvalidOperationException(String.Format("{0} is not a valid Enum!", e.GetType()));

You have 2 problems here, the first is how to localize enums which is solved by Localizing enum descriptions attributes.
The second is how to display the localized name whilst using the enum's value. This can be solved by creating a simple wrapper object such as:
public sealed class NamedItem
{
private readonly string name;
private readonly object value;
public NamedItem (string name, object value)
{
this.name = name;
this.value = value;
}
public string Name { get { return name; } }
public object Value { get { return value; } }
public override string ToString ()
{
return name;
}
}
This provides a generic re-usable class for any drop down box where you might want to show a different name for an item than the item itself provides (eg enums, ints, etc).
Once you have this class, you can set the drop down's DisplayMember to Name and ValueMember to Value. This will mean that dropdown.SelectedValue will still return your enum.

I know this question is old, but this may help some people.
You can just handle the Format event of the ComboBox control (http://msdn.microsoft.com/en-us/library/system.windows.forms.listcontrol.format.aspx), and add your text logic in it.
private void ComboBoxFormat(object sender, ListControlConvertEventArgs e)
{
e.Value = GetDescription(e.Value);
}
public static string GetDescription(object item)
{
string desc = null;
Type type = item.GetType();
MemberInfo[] memInfo = type.GetMember(item.ToString());
if (memInfo != null && memInfo.Length > 0)
{
object[] attrs = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs != null && attrs.Length > 0)
{
desc = (attrs[0] as DescriptionAttribute).Description;
}
}
if (desc == null) // Description not found
{
desc = item.ToString();
}
return desc;
}
With this, the ComboBox control still holds enum values rather than strings.

Related

Shorten syntax for nearly identical properties

I have to rework some code and stumbled upon a few classes which define a huge amount of very similar properties.
They look something like this:
public _ReturnType _PropertyName
{
get
{
IMarkerInterface value = null;
if (Properties != null) Properties.TryGetValue(_string, out value);
return value as _ReturnType;
}
set { Properties[_string] = value; }
}
The only difference between them is the _ReturnType, the _string that is used in the dictionary Properties and obviously the _PropertyName.
I was wondering if there is a way to shorten the syntax?
If you see duplicate code, you extract a method. It would look something like this:
private T GetValueOrDefault<T>(string key)
{
IMarkerInterface value = null;
if (Properties != null) Properties.TryGetValue(key, out value);
return value as T;
}
Then change your getter:
get
{
return GetValueOrDefault<_ReturnType>("key");
}
But if this code is spread out over multiple classes, you'd have to define a base class containing the Properties property and the above GetValueOrDefault() method, albeit protected instead of private.
Alternatively, you'd define it as an extension method on whatever the type of Properties is:
public static T GetValueOrDefault<T>(this IDictionary<string, IMarkerInterface> properties, string key)
{
IMarkerInterface value = null;
if (properties != null) properties.TryGetValue(key, out value);
return value as T;
}
And call it as such:
get
{
return Properties.GetValueOrDefault<_ReturnType>("key");
}
But, as #Daniel comments, this smells like an ideal scenario for code generation, because without that you'd still have a couple of lines of (copy-pasted, error-prone) code.
There probably is a source somewhere for what these properties should be named, and you can use something like T4 templates to generate this code file from it.
Well, you could do this:
private IMarkerInterface getIMF(string str)
{
IMarkerInterface value = null;
Properties?.TryGetValue(_string, out value);
return value;
}
public _ReturnType _PropertyName
{
get { return getIMF(_string) as _ReturnType; }
set { Properties[_string] = value; }
}
If Properties implements IReadOnlyDictionary<string, object> (like a Dictionary<string, object> for instance), one thing you could do is add an extension method:
public static TValue TryGetValue<TValue>(
this IReadOnlyDictionary<string, object> properties,
string key)
where TValue : class
{
if ((properties != null) &&
properties.TryGetValue(key, out object value))
{
return value as TValue;
}
return null;
}
and then
public IMarkerInterface MarkerInterface
{
get => Properties.TryGetValue<IMarkerInterface>("MarkerInterface");
set { Properties["MarkerInterface"] = value; }
}
Link to Fiddle

Generic Enum to SelectList extension method

I need to create a SelectList from any Enum in my project.
I have the code below which I create a select list from a specific enum, but I'd like to make an extension method for ANY enum. This example retrieves the value of the DescriptionAttribute on each Enum value
var list = new SelectList(
Enum.GetValues(typeof(eChargeType))
.Cast<eChargeType>()
.Select(n => new
{
id = (int)n,
label = n.ToString()
}), "id", "label", charge.type_id);
Referencing this post, how do I proceed?
public static void ToSelectList(this Enum e)
{
// code here
}
What I think you are struggling with, is the retrieval of the description. I'm sure once you have those that you can define your final method which gives your exact result.
First, if you define an extension method, it works on a value of the enum, not on the enum type itself. And I think, for easy of usage, you would like to call the method on the type (like a static method). Unfortunately, you cannot define those.
What you can do is the following. First define a method which retrieves the description of the enum value, if it has one:
public static string GetDescription(this Enum value) {
string description = value.ToString();
FieldInfo fieldInfo = value.GetType().GetField(description);
DescriptionAttribute[] attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes != null && attributes.Length > 0) {
description = attributes[0].Description;
}
return description;
}
Next, define a method which takes all values of an enum, and use the previous method to look up the value which we want to show, and return that list. The generic argument can be inferred.
public static List<KeyValuePair<TEnum, string>> ToEnumDescriptionsList<TEnum>(this TEnum value) {
return Enum
.GetValues(typeof(TEnum))
.Cast<TEnum>()
.Select(x => new KeyValuePair<TEnum, string>(x, ((Enum)((object)x)).GetDescription()))
.ToList();
}
And finally, for ease of usage, a method to call it directly without value. But then the generic argument is not optional.
public static List<KeyValuePair<TEnum, string>> ToEnumDescriptionsList<TEnum>() {
return ToEnumDescriptionsList<TEnum>(default(TEnum));
}
Now we can use it like this:
enum TestEnum {
[Description("My first value")]
Value1,
Value2,
[Description("Last one")]
Value99
}
var items = default(TestEnum).ToEnumDescriptionsList();
// or: TestEnum.Value1.ToEnumDescriptionsList();
// Alternative: EnumExtensions.ToEnumDescriptionsList<TestEnum>()
foreach (var item in items) {
Console.WriteLine("{0} - {1}", item.Key, item.Value);
}
Console.ReadLine();
Which outputs:
Value1 - My first value
Value2 - Value2
Value99 - Last one
Late to the party, but since there is no accepted answer and it might help others:
As #Maarten mentioned, an extension method works on the value of an enum, not the enum type itelf, so as with Maarteen's soultion you can create a dummy or default value to call the extension method on, however, you may find, as I did, that it is simpler to just use a static helper method like so:
public static class EnumHelper
{
public static SelectList GetSelectList<T>(string selectedValue, bool useNumeric = false)
{
Type enumType = GetBaseType(typeof(T));
if (enumType.IsEnum)
{
var list = new List<SelectListItem>();
// Add empty option
list.Add(new SelectListItem { Value = string.Empty, Text = string.Empty });
foreach (Enum e in Enum.GetValues(enumType))
{
list.Add(new SelectListItem { Value = useNumeric ? Convert.ToInt32(e).ToString() : e.ToString(), Text = e.Description() });
}
return new SelectList(list, "Value", "Text", selectedValue);
}
return null;
}
private static bool IsTypeNullable(Type type)
{
return (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>));
}
private static Type GetBaseType(Type type)
{
return IsTypeNullable(type) ? type.GetGenericArguments()[0] : type;
}
You would create the select list like this:
viewModel.ProvinceSelect = EnumHelper.GetSelectList<Province>(model.Province);
or using the optional numeric values instead of strings:
viewModel.MonthSelect = EnumHelper.GetSelectList<Month>(model.Month,true);
The basic idea for this I got from here, though I changed it to suit my needs. One thing I added was the ability to optionally use ints for the value. I also added an enum extension to get the description attribute which is based on this blog post:
public static class EnumExtensions
{
public static string Description(this Enum en)
{
Type type = en.GetType();
MemberInfo[] memInfo = type.GetMember(en.ToString());
if (memInfo != null && memInfo.Length > 0)
{
object[] attrs = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs != null && attrs.Length > 0)
{
return ((DescriptionAttribute)attrs[0]).Description;
}
}
return en.ToString();
}
}
Since enum can't have extensions pinned to the entire collection a convenient way to extend the Enum base class is with a static typed class. This will allow concise code such as:
Enum<MyCustomEnumType>.GetSelectItems();
Which can be achieved with the following code:
public static class Enum<T>
{
public static SelectListItem[] GetSelectItems()
{
Type type = typeof(T);
return
Enum.GetValues(type)
.Cast<object>()
.Select(v => new SelectListItem() { Value = v.ToString(), Text = Enum.GetName(type, v) })
.ToArray();
}
}
Since enum do not have a shared interface Type misuse is possible, but the class name Enum should dispell any confusion.
Here is a corrected [type casted value to int] and simplified [uses tostring override instead of getname] version of Nathaniels answer that returns a List instead of an array:
public static class Enum<T>
{
//usage: var lst = Enum<myenum>.GetSelectList();
public static List<SelectListItem> GetSelectList()
{
return Enum.GetValues( typeof(T) )
.Cast<object>()
.Select(i => new SelectListItem()
{ Value = ((int)i).ToString()
,Text = i.ToString() })
.ToList();
}
}

How to manipulate the properties of a user-defined class on runtime?

I have a huge user-defined class with lots of properties and some of them has to be set with a certain value.
To be more specific, all the public properties with the type of string in this user-defined class have to be "emptied" at the end of execution.
So i reached all the public properties one by one (like 300 properties) and assigned them with my 300 lines of code. What i did to solve this problem, did what i needed, but didn't satisfy me of course.
So i decided to write a Helper Method (as Extension Method) in C# that iterates through the properties of an object instance and access / manipulate them dynamically. I've seen some similar questions about iterating through properties in here, but didn't see anything about changing property values so far. Here is what i tried:
public static void SetDefaultStringValues(this Object myObject)
{
PropertyInfo[] aryProperties = entityObject.GetType().GetProperties();
foreach (object property in aryProperties)
{
if (property is String)
{
//property = String.Empty;
}
}
}
The commented part had to be the line that i set the variables but that wasn't really a success story :) I'll appreciate any help.
Use PropertyInfo.SetValue method, more on this in here
You can use PropertyDescriptor of System.ComponentModel for lazy coding. Assuming you want to iterate over public instance methods (not statics) you can try the following sample:
Test class:
public class TestClass
{
private int mIntMemeber = 0; // # to test int type
private string mStringMember = "abc"; // # to test string type (initialized)
private string mNullStringMember = null; // # to test string type (null)
private static string mStaticNullStringMember; // # to test string type (static)
// # Defining properties for each member
public int IntMember
{
get { return mIntMemeber; }
set { mIntMemeber = value; }
}
public string StringMember
{
get { return mStringMember; }
set { mStringMember = value; }
}
public string NullStringMember
{
get { return mNullStringMember; }
set { mNullStringMember = value; }
}
public static string StaticNullStringMember
{
get { return mStaticNullStringMember; }
set { mStaticNullStringMember = value; }
}
}
SetDefaultStringValues() Extension Method:
public static string SetDefaultStringValues(this TestClass testClass)
{
StringBuilder returnLogBuilder = new StringBuilder();
// # Get all properties of testClass instance
PropertyDescriptorCollection propDescCollection = TypeDescriptor.GetProperties(testClass);
// # Iterate over the property collection
foreach (PropertyDescriptor property in propDescCollection)
{
string name = property.Name;
Type t = property.PropertyType; // # Get property type
object value = property.GetValue(testClass); // # Get value of the property (value that member variable holds)
if (t == typeof(string)) // # If type of propery is string and value is null
{
property.SetValue(testClass, String.Empty); // # Set value of the property (set member variable)
value = String.Empty; // # <-- To prevent NullReferenceException when printing out
}
returnLogBuilder.AppendLine("*****\nName:\t{0}\nType:\t{1}\nValue:\t{2}", name, t.ToString(), value.ToString());
}
returnLogBuilder.AppendLine("*****");
return returnLogBuilder.toString();
}
You could also check if value is null within the loop. SetDefaultStringValues method parameter could be any object instance. You can change it to SetDefaultStringValues(this object o) and use it as extension method for your defined class instance.
You need a different syntax in order to check the property type; furthermore, you shold check that the property has a public setter.
if (property.PropertyType == typeof(string) && property.GetSetMethod() != null)
property.SetValue(entityObject, "");
foreach (PropertyInfo property in aryProperties)
{
if (property.PropertyType == typeof(string) && property.CanWrite)
{
property.SetValue(myObject, "", null);
}
}

Convert an enum to List<string>

How do I convert the following Enum to a List of strings?
[Flags]
public enum DataSourceTypes
{
None = 0,
Grid = 1,
ExcelFile = 2,
ODBC = 4
};
I couldn't find this exact question, this Enum to List is the closest but I specifically want List<string>?
Use Enum's static method, GetNames. It returns a string[], like so:
Enum.GetNames(typeof(DataSourceTypes))
If you want to create a method that does only this for only one type of enum, and also converts that array to a List, you can write something like this:
public List<string> GetDataSourceTypes()
{
return Enum.GetNames(typeof(DataSourceTypes)).ToList();
}
You will need Using System.Linq; at the top of your class to use .ToList()
I want to add another solution:
In my case, I need to use a Enum group in a drop down button list items. So they might have space, i.e. more user friendly descriptions needed:
public enum CancelReasonsEnum
{
[Description("In rush")]
InRush,
[Description("Need more coffee")]
NeedMoreCoffee,
[Description("Call me back in 5 minutes!")]
In5Minutes
}
In a helper class (HelperMethods) I created the following method:
public static List<string> GetListOfDescription<T>() where T : struct
{
Type t = typeof(T);
return !t.IsEnum ? null : Enum.GetValues(t).Cast<Enum>().Select(x => x.GetDescription()).ToList();
}
When you call this helper you will get the list of item descriptions.
List<string> items = HelperMethods.GetListOfDescription<CancelReasonEnum>();
ADDITION:
In any case, if you want to implement this method you need :GetDescription extension for enum. This is what I use.
public static string GetDescription(this Enum value)
{
Type type = value.GetType();
string name = Enum.GetName(type, value);
if (name != null)
{
FieldInfo field = type.GetField(name);
if (field != null)
{
DescriptionAttribute attr =Attribute.GetCustomAttribute(field,typeof(DescriptionAttribute)) as DescriptionAttribute;
if (attr != null)
{
return attr.Description;
}
}
}
return null;
/* how to use
MyEnum x = MyEnum.NeedMoreCoffee;
string description = x.GetDescription();
*/
}
In my case, I need to convert it as SelectItem for Checkbox and Radio Button
public class Enum<T> where T : struct, IConvertible
{
public static List<SelectItem> ToSelectItems
{
get
{
if (!typeof(T).IsEnum)
throw new ArgumentException("T must be an enumerated type");
var values = Enum.GetNames(typeof(T));
return values.Select((t, i) => new SelectItem() {Id = i, Name = t}).ToList();
}
}
}

more elegant design about enum

I'm on learning for C#.
I heared C# is one of the most constructible language. so would you guys make my code more elegant and efficient?
public class ISO639
{
public enum ISO639Code
{
Afrikaans, //af
Albanian, //sq
Amharic, //am
...
Yiddish, //yi
Unknown
}
public static string GetISO639CodeString(ISO639.ISO639Code l)
{
switch (l)
{
case ISO639Code.English: return "en";
case ISO639Code.Japanese: return "ja";
...
case ISO639Code.Hebrew: return "he";
default: return "";
}
public static ISO639.ISO639Code GetISO39CodeValue(string s)
{
switch (s)
{
case "ko" : return ISO639Code.Korean;
case "en" : return ISO639Code.English;
...
case "hu" : return ISO639Code.Hungarian;
default: return ISO639Code.Unknown;
}
}
}
Here is a my class ISO639. This class provides enum for ISO639 code, but I need a type conversion on from ISO639 enum to plain string. (ex. ISO639.ISO639Code.Italian => "it"). I also need a type conversion from plain string to ISO639 enum. (ex. "it" => ISO639.ISO639Code.Italian).
Is there a more efficient coding style for that?
You can add standard System.ComponentModel.Description attribute to each enum entry and then read it.
public enum ISO639Code
{
[Description("af")]
Afrikaans
}
public static class EnumExtensions
{
// Extension method to read Description value
public static string GetDescription(this Enum currentEnum)
{
var fi = currentEnum.GetType().GetField(currentEnum.ToString());
var da = (DescriptionAttribute)Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute));
return da != null ? da.Description : currentEnum.ToString();
}
}
// **How-to read it**
ISO639Code isoCode = ISO639Code.Afrikaans;
// this will returns "af"
string isoDescription = isoCode.GetDescription();
EDIT:
string searchFor = "af";
ISO639Code foundEntry;
// Loop through all entries descriptions
var allEntries = Enum.GetValues(typeof(ISO639Code));
foreach (var entry in allEntries)
{
// If you will extract this as separate method and use it for search not only loop
// through the all entries - you can put here is yield return description
var currentEntry = ((ISO639Code)entry);
string description = currentEntry.GetDescription();
if (description == searchFor)
{
foundEntry = currentEntry;
break;
}
}
Sure. You can use attributes:
public enum ISO639Code
{
[CodeString("af")] Afrikaans,
[CodeString("sq")] Albanian,
}
Use dictionary, for example: new Dictionary<ISO639Code, string>.
I suggest you to use C# extension methods to enums, they allow you to add whatever logic you want.
For example, see http://pietschsoft.com/post/2008/07/c-enhance-enums-using-extension-methods.aspx
I'd simply store the information in a dictionary-like object. This way you can reference the name by key and get the value directly.
You have an enum:
public enum ISO639Code
{
Afrikaans = 1,
Albanian = 2,
Amharic = 3,
etc.
Create a database table:
ISO639Id int PK,
ISO639Code char(2)
Where the ISO639Id maps to the value of the enum.
In code you'd want a ISO630 Class containing Id and Code values read from the database.
(You can load this once and then cache it in memory.)
The beauty of this approach, is it can be easily extended so that if in future you wanted to store more pieces of information for each ISO639 code, you could simply add another field.
Look at System.Globailzation namespace. The functionality you require looks to be already implemented there. At worst you can see the architecture and technique applied in the .Net framework to solve a very similar problem.
Enumerations are really good to work in code, as they are really strongly typed and make refactoring easier.
Follow these steps:
Use attributes for whatever extra information you want to attach to an enum. Usually this is a simple Description attribute. Something like:
public enum IsoCodes
{
[Description("af")]
Africans = 0,
[Description("am")]
Americans = 1
}
Then write some extension methods to convert strings and integers to and from this enum:
public static string GetDescription(this Enum value)
{
var entries = value.ToString().Split(FlagEnumSeparatorCharacter);
var description = new string[entries.Length];
for (var i = 0; i < entries.Length; i++)
{
var fieldInfo = value.GetType().GetField(entries[i].Trim());
var attributes = fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false) as DescriptionAttribute[];
description[i] = (attributes.Length > 0) ? attributes[0].Description : entries[i].Trim();
}
return String.Join(", ", description);
}
public static int GetValue(this Enum value)
{
return (int)value.GetType().GetField(value.ToString()).GetRawConstantValue();
}
public static T ToEnum<T>(this string value)
{
if (typeof(T).BaseType.Name != typeof(Enum).Name)
{
throw new Exception("Not an enum");
}
return (T)Enum.Parse(typeof(T), value, true);
}
public static T ToEnum<T>(this int value)
{
if (typeof(T).BaseType.Name != typeof(Enum).Name)
{
throw new Exception("Not an enum");
}
return (T)Enum.ToObject(typeof(T), value);
}
Now use your enums as you like.
I would go with having ISO639Code as class instead of enum:
public class ISO639Code
{
public string Value { get; set ; }
public string Code { get; set; }
public ISO639Code()
{
this.Value = "";
this.Code = "";
}
public ISO639Code(string value, string code)
: this()
{
this.Value = value;
this.Code = code;
}
public override bool Equals(object obj)
{
if (obj != null)
{
if (obj is string)
return obj.ToString().Equals(this.Value, StringComparison.CurrentCultureIgnoreCase);
if (obj is ISO639Code)
return ((ISO639Code)obj).Value.Equals(this.Value, StringComparison.CurrentCultureIgnoreCase);
}
return false;
}
public override int GetHashCode()
{
return this.Value.GetHashCode();
}
public override string ToString()
{
return this.Value;
}
}
Then have global List<ISO639Code> with all possible codes, and to find specific code based on code name or value, just search for this in the List.
Personally, I prefer this over tweaking the enum.

Categories

Resources