Is there a way of determining the name of a constant from a given value?
For example, given the following:
public const uint ERR_OK = 0x00000000;
How could one obtain "ERR_OK"?
I have been looking at refection but cant seem to find anything that helps me.
In general, you can't. There could be any number of constants with the same value. If you know the class which declared the constant, you could look for all public static fields and see if there are any with the value 0, but that's all. Then again, that might be good enough for you - is it? If so...
public string FindConstantName<T>(Type containingType, T value)
{
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
foreach (FieldInfo field in containingType.GetFields
(BindingFlags.Static | BindingFlags.Public))
{
if (field.FieldType == typeof(T) &&
comparer.Equals(value, (T) field.GetValue(null)))
{
return field.Name; // There could be others, of course...
}
}
return null; // Or throw an exception
}
I may be late.. but i think following could be the answer
public static class Names
{
public const string name1 = "Name 01";
public const string name2 = "Name 02";
public static string GetName(string code)
{
foreach (var field in typeof(Names).GetFields())
{
if ((string)field.GetValue(null) == code)
return field.Name.ToString();
}
return "";
}
}
and following will print "name1"
string result = Names.GetName("Name 01");
Console.WriteLine(result )
You may be interested in Enums instead, which can be programmatically converted from name to value and vice versa.
You won't be able to do this since constants are replaced at compilation time with their literal values.
In other words the compiler takes this:
class Foo
{
uint someField = ERR_OK;
}
and turns it into this:
class Foo
{
uint someField = 0;
}
I don't think you can do that in a deterministic way. What if there are multiple constants with the same value?
I suggest you use an enum to represent your constant.
Or
string ReturnConstant(uint val)
{
if(val == 0x00000000)
return "ERR_OK";
else
return null;
}
The easiest way would be to switch to using an enum
Related
I have enum:
enum MyEnum{
aaaVal1,
aaaVal2,
aaaVal3,
}
I need to have abbreviated version of 'MyEnum' which maps every item from 'MyEnum' to different values. My current approach is method which simply translates every item:
string translate(MyEnum myEnum)
{
string result = "";
switch ((int)myEnum)
{
0: result = "abc";
1: result = "dft";
default: result = "fsdfds"
}
return result;
}
the problem with this approach is that every time programmer changes MyEnum he should also change translate method.
This is not a good way of programming.
So..
Is there any more elegant solution for this problem?
Thank you :-)
Four options:
Decorate your enum values with attributes, e.g.
enum MyEnum
{
[Description("abc")]
AaaVal1,
[Description("dft")]
AaaVal2,
AaaVal3,
}
Then you can create a mapping (like the dictionary solution below) via reflection.
Keep the switch statement but switch on the enum value instead of a number for better readability:
switch (myEnum)
{
case MyEnum.AaaVal1: return "abc";
case MyEnum.AaaVal2: return "dft";
default: return "fsdfds";
}
Create a Dictionary<MyEnum, string>:
private static Dictionary<MyEnum, string> EnumDescriptions =
new Dictionary<MyEnum, string>
{
{ MyEnum.AaaVal1, "abc" },
{ MyEnum.AaaVal2, "dft" },
};
You'd need to handle the defaulting in the method, of course.
Use a resource file, with an entry for each string representation. This would be better if you're really trying to translate in a way that might need different translations for different cultures.
Considering that the use of descriptors on enums is quite common, here it's a good-enough class to do it:
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
class EnumDescriptor : Attribute
{
public readonly string Description;
public EnumDescriptor(string description)
{
this.Description = description;
}
public static string GetFromValue<T>(T value) where T : struct
{
var type = typeof(T);
var memInfo = type.GetField(value.ToString());
var attributes = memInfo.GetCustomAttributes(typeof(EnumDescriptor), false);
if (attributes.Length == 0)
{
return null;
}
return ((EnumDescriptor)attributes[0]).Description;
}
}
enum MyEnum
{
[EnumDescriptor("Hello")]
aaaVal1,
aaaVal2,
aaaVal3,
}
string translate(MyEnum myEnum)
{
// The ?? operator returns the left value unless the lv is null,
// if it's null it returns the right value.
string result = EnumDescriptor.GetFromValue(myEnum) ?? "fsdfds";
return result;
}
I'm finding what you're trying to do a bit weird.
If you're making translations, then you should create a RESX file and create ACTUAL translations.
But to answer your question, I guess you could create another enum with the same amount of fields and same numbering (if you're using anything other than the default) and have that act as the abbreviated names. Connecting one to the other should be straightforward:
string GetAbbreviation(Enum1 enum1)
{
return ((Enum2)((int)enum1)).ToString();
}
Attributes will be nice solution for this case. You can specify translations for enumeration members via declarative way:
public class TranslateAttribute
{
public string Translation { get; private set; }
public TranslateAttribute(string translation)
{
Translation = translation;
}
}
enum MyEnum
{
[Translate("abc")]
aaaVal1,
[Translate("dft")]
aaaVal2,
[Translate("fsdfds")]
aaaVal3
}
After this you should write common method for obtaining translations. It should check attribute with translation (via reflection) and return translation if it was specified and default value in other cases.
I have enums like the following in my DB:
"Random Type", "Random Type1", "NewRandom"
Normally, I would represent the values in an enum like:
enum myTypes
{
Random Type = 0,...
}
but this is not possible, so I tried using a class
static class myTypes
{
public const string RandomType = "Random Type";
public const string NewRandom = "NewRandom";
}
This way, I can use the class like an Enum, but I'm wondering if this is the best implementation possible? Or is there away around creating Enums to allow space?
Thanks.
EDIT:
Please, I would also love to know whether there is anything wrong with my current implementation. I have a feeling my current implementation is better than most suggested solutions here.
Thanks
No, you can't do that. Enums are just typesafe ints.
There is a solution available, and I quite like it. Use the DescriptionAttribute.
You'd use it like this:
static enum myTypes
{
[Description("Random Type")]
RandomType,
[Descripton("New Random")]
NewRandom
}
and then you'd also need this extension method:
public static string GetDescription<T>(this T en) where T : struct, IConvertible
{
Type type = typeof(T);
if (!type.IsEnum)
{
throw new ArgumentException("The type is not an enum");
}
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();
}
And then with that, you could just do this:
myTypes.RandomType.GetDescription();
Enums are much similar to numbers (Integers specifically), rather than strings or so. Adhering to numbered Enums yields you to easy casting, flags-composition (e.g. AND, OR, etc).
I wouldn't use string constant in place of Enums, unless that will bring you more benefits than penalties.
If your goal is to describe to the user the Enum options, I'd suggest to consider to enrich each item with a Description attribute. It's a metadata, rather a real data, but it's also pretty easy to read using reflection.
Cheers
What I do is I define custom attribute [DisplayName(string)] that can be attached to enum values. You define your enum with display name on the values you wish were named with spaces / special characters:
public enum Test
{
None = 0,
[DisplayName("My Value")]
MyValue = 1,
[DisplayName("Spęćiał")]
Special = 2
}
Your implementation in addition to getting enum value name should also check if DisplayName attribute is set, and if so, it should take display name instead.
I would go with display name attributes:
[AttributeUsage(AttributeTargets.Field)]
public class EnumDisplayNameAttribute : DisplayNameAttribute
{
public EnumDisplayNameAttribute()
: base(string.Empty)
{
}
public EnumDisplayNameAttribute(string displayName)
: base(displayName)
{
}
}
public static class EnumExtensions
{
public static string ToDisplayName(this Enum enumValue)
{
var builder = new StringBuilder();
var fields = GetEnumFields(enumValue);
if (fields[0] != null)
for (int i = 0; i < fields.Length; i++)
{
var value = fields[i]
.GetCustomAttributes(typeof(EnumDisplayNameAttribute), false)
.OfType<EnumDisplayNameAttribute>()
.FirstOrDefault();
builder.Append(value != null
? value.DisplayName
: enumValue.ToString());
if (i != fields.Length - 1)
builder.Append(", ");
}
return builder.ToString();
}
private static FieldInfo[] GetEnumFields(Enum enumValue)
{
var type = enumValue.GetType();
return enumValue
.ToString()
.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
.Select(type.GetField)
.ToArray();
}
}
usage for type:
public enum MyType
{
[DisplayName("Random Type")]
RandomType,
[DisplayName("New Random")]
NewRandom
}
would be:
var enumVariable = MyType.RandomType;
var stringRepresentation = enumVariable.ToDisplayName();
note that with that approach you would get ToString values if you omit attribute for some enum members.
You should probably not use strings as type indicators in your database. Use integers instead. If you like, you can have a "type table" in your database, where you can store the type names, instead of repeating them through the tables that uses them.
If you do this, then you can convert the integers from the database to enums as suggested above.
You can use Typesafe Enum pattern to achieve your goal.
Idea is to wrap your enum around a class. I guess this is what you want -
public class MyTypes
{
#region Enum Values
public static MyTypes RandomType = new MyTypes(0, "Random Type");
public static MyTypes NewRandom = new MyTypes(1, "New Random");
#endregion
#region Private members
private int id;
private string value;
private MyTypes(int id, string value)
{
this.id = id;
this.value = value;
}
#endregion
#region Overriden members
public override string ToString()
{
return value;
}
#endregion
public static List<MyTypes> GetValues()
{
return new List<MyTypes>() { MyTypes.RandomType, MyTypes.NewRandom };
}
}
If I have the following:
public enum TYPE
{
One = 1,
Two = 2,
Three = 3
}
When I do:
var a = TYPE.One;
I would like it to populate the variable a with a string in the format "01". In other words two digits with a leading zero.
Is it possible to do this by assigning some method to the SomeEnum? I realized I could use TYPE.One.ToString("00")but I would like to have it self-contained in the enum and something very simple to use.
You can add a string to each enum element using the description attribute.
e.g.
public Enum MyEnum
{
[Description("Value A Description")]
ValueA,
[Description[("Value B Description")]
ValueB
}
To retrieve the description value, use an extender class
public static class MyEnumExtender
{
public static string Description(this Enum Value)
{
FieldInfo FI = Value.GetType().GetField(Value.ToString());
IEnumerable<DescriptionAttribute> Attributes = FI.GetCustomAttributes(typeof(DescriptionAttribute), false).Cast<DescriptionAttribute>();
return (Attributes.Any()) ? Attributes.First().Description : Value.ToString();
}
}
....
MyEnum EnumVar = MyEnum.ValueA;
string Description = EnumVar.Description();
can do something like this :
public static class Ext {
public static string ToMyString(this Enumer en ) {
return ((int)en).ToString("00");
}
}
and after use this like:
public enum TYPE { One = 1, Two = 2, Three = 3 }
Type t = TYPE.One;
string s = t.ToMyString();
Yes, conceptually it's the same as like declaring a string , but it's hidden inside extension method.
Other solution is: to simply avoid, at this point, using enums in that way.
Don't use enums for that, but something like a Dictionary or Hash. Enums are there when there is a limited set of possibilities and you do not want or need a value. How it is stored is irrelevant.
I need my enum to return a specific string, but I can't work out how to make it return a string with breaks in it without having a method to do the conversion. Is it possible to make LicenseTypes.DISCOUNT_EARLY_ADOPTER return DISCOUNT EARLY-ADOPTER without the helper method?
// All license types
public enum LicenseTypes
{
DISCOUNT,
DISCOUNT_EARLY_ADOPTER,
COMMERCIAL,
COMMERCIAL_EARLY_ADOPTER
}
// Convert enum to correct string
public static string LicenseTypeToString(LicenseTypes Enum)
{
if (Enum == LicenseTypes.COMMERCIAL)
return "COMMERCIAL";
else if (Enum == LicenseTypes.COMMERCIAL_EARLY_ADOPTER)
return "COMMERCIAL EARLY-ADOPTER";
else if (Enum == LicenseTypes.DISCOUNT)
return "DISCOUNT";
else if (Enum == LicenseTypes.DISCOUNT_EARLY_ADOPTER)
return "DISCOUNT EARLY-ADOPTER";
else
return "ERROR";
}
Firstly, a separate option from a helper method is simply to have a Dictionary<LicenseTypes, string> which you populate once. That would probably be the simplest approach, to be honest:
private static readonly Dictionary<LicenseTypes, string> LicenseDesciptions =
new Dictionary<LicenseTypes, string>
{
{ LicenseTypes.COMMERCIAL, "COMMERCIAL" },
{ LicenseTypes.COMMERCIAL_EARLY_ADOPTER, "COMMERCIAL EARLY-ADOPTER" },
{ LicenseTypes.DOMESTIC, "DOMESTIC" },
{ LicenseTypes.DOMESTIC_EARLY_ADOPTER, "DOMESTIC EARLY-ADOPTER" },
};
(As noted in comments, another alternative is a switch/case... but I personally prefer this way, as effectively you've got a data mapping, so it makes sense to use a data structure rather than an execution flow structure. It also means you can swap out dictionaries for different languages etc if you want.)
Secondly, one option would be to decorate each enum value with a [Description] attribute (or your own attribute if you want), and find that out with reflection - Unconstrained Melody has an extension method which can do that very easily:
// Throws ArgumentOutOfRangeException if the licenseType value isn't defined
// or doesn't have a description.
string description = licenseType.GetDescription();
Also, following .NET naming conventions it should be:
public enum LicenseType // Singular as it's not a Flags enum
{
Discount,
DiscountEarlyAdopter,
Commercial,
CommercialEarlyAdopter
}
A little reflection, and Attribute magic, and this should just answer it :)
Getting attributes of Enum's value
Might also make it an extension method.
here's how it should look (also added generics):
public static class MyExtensionsClass
{
public static string ToDescriptionString<T>(this T val)
where T : struct, IConvertible
{
if (typeof(T).IsEnum)
{
var type = val.GetType();
var memInfo = type.GetMember(val.ToString());
var attributes = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
return ((DescriptionAttribute)attributes[0]).Description;
}
return ""; //all paths must return a value
}
}
public enum LicenseTypes
{
[Description("DISCOUNT")]
DISCOUNT,
[Description("DISCOUNT EARLY-ADOPTER")]
DISCOUNT_EARLY_ADOPTER,
[Description("COMMERCIAL")]
COMMERCIAL,
[Description("COMMERCIAL EARLY-ADOPTER")]
COMMERCIAL_EARLY_ADOPTER
}
Thank you, guys that wrote these:
Enhance enums using extension methods
Create Generic method constraining T to an Enum
Good luck!
While it doesn't eliminate the helper method, note that in your case you could just special-case the values that you can't get using ToString:
switch (Enum) {
case LicenseTypes.COMMERCIAL_EARLY_ADOPTER:
return "COMMERCIAL EARLY-ADOPTER";
case LicenseTypes.DISCOUNT_EARLY_ADOPTER:
return "DISCOUNT EARLY-ADOPTER";
default
return Enum.ToString();
}
I use this from Google's dotnet client - StringValueAttribute.cs
and Utilities.cs
public enum LicenseType
{
[StringValue("DISCOUNT")] Discount,
[StringValue("DISCOUNT EARLY-ADOPTER")] DiscountEarlyAdopter,
[StringValue("COMMERCIAL")] Commercial,
[StringValue("COMMERCIAL EARLY-ADOPTER")] CommercialEarlyAdopter
}
Then you can simply do this:
licenseType.GetStringValue();
Convert to string using "G" format, then replace "_" (underscore) with spaces:
LicensceTypes license = LicenseTypes.COMMERCIAL_EARLY_ADOPTERS;
string licenseDescription = license.ToString("G").Replace('_', ' ');
// licenseDescription = "COMMERCIAL EARLY ADOPTERS"
I think I would use a class to avoid this scenario. :/
public class LicenceType
{
private string name;
public LicenceType(string Name)
{
this.name = Name;
}
public override string ToString()
{
return name;
}
}
public static class LicenceTypes
{
public static LicenceType DISCOUNT = new LicenceType("DISCOUNT");
public static LicenceType DISCOUNT_EARLY_ADOPTER= new LicenceType("DISCOUNT EARLY-ADOPTER");
public static LicenceType COMMERCIAL= new LicenceType("COMMERCIAL");
public static LicenceType COMMERCIAL_EARLY_ADOPTER= new LicenceType("COMMERCIAL EARLY-ADOPTER");
}
I'm creating this selectbox in a SharePoint web part and need to have a drop down with the current version so I need to use an Enum.
public enum SelectVersionEnum { 2010, 2007 };
Well you can see where it breaks, is there any way to use integers in a enum?
Most of all I'd like to use
public enum SelectVersionEnum { 2010=14, 2007=12 };
No, you can not name enums with integer names.
An enum value name is a normal identifier and must follow the same rules as everything else.
You can, however, use:
public enum SelectVersionEnum
{
Version2007 = 12,
Version2010 = 14
}
Additionally, Enum.Parse can parse strings with integers into their corresponding enum value, even if value described in the string doesn't exist.
Try the following in LINQPad:
void Main()
{
Enum.Parse(typeof(SelectVersionEnum), "12").Dump();
Enum.Parse(typeof(SelectVersionEnum), "14").Dump();
Enum.Parse(typeof(SelectVersionEnum), "2007").Dump();
}
public enum SelectVersionEnum
{
Version2007 = 12,
Version2010 = 14
}
The output:
Version2007
Version2010
2007
What do you think would've happened if you defined the following:
public enum SelectVersionEnum
{
12 = 14,
14 = 16
}
Does the string "14" now mean "12" or "14"?
Enum members must be valid C# identifiers.
They cannot start with numbers.
Instead, you can use something like Office2007, Office2010 or V2007, V2010.
No, enum identifiers can't start with a numeric character.
You can add an extension method to your enum like any other type.
So you could create an extension for your SelectVersionEnum to help you get the enum values in the right format...
public static class SelectVersionEnumExtension
{
public static int Version(this SelectVersionEnum enumValue)
{
return 0; // Obviously you should return something meaningful here..
}
}
This gives you a lot of flexibilty.
One way you could have numeric values associated with enums is by using the description attribute. For example you might have the enum:
[Serializable]
public enum SelectVersionEnum
{
[Description("2007")]
v2007,
[Description("2010")]
v2010
}
You could then write an extension method to get the numeric value you are looking for.
public static string Description(this Enum value)
{
var type = value.GetType();
var name = Enum.GetName(type, value);
if (name != null)
{
if (type.GetField(name) != null)
{
var attr = Attribute.GetCustomAttribute(type.GetField(name), typeof(DescriptionAttribute)) as DescriptionAttribute;
return attr != null ? attr.Description : name;
}
}
return null;
} // end
You would use it like this:
var version = SelectVersionEnum.v2007.Description();