0

I want to check in Enum that passed code exists in any of enum or not. Problem is my enum defined is like below with using code attribute.

public enum TestEnum
    {

        None,

        [Code("FMNG")]
        FunctionsManagement,

        [Code("INST_MAST_MGT")]
        MasterInstManagement
}

[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
    public class CodeAttribute : Attribute
    {
        readonly string _code;
        public string Code
        {
            get
            {
                return _code;
            }
        }
        public CodeAttribute(string code)
        {
            _code = code;
        }
    }

Now, I have string available (e.g. "FMNG") and I want to search that enum back that enum exists with passed string which will be in enum attribute.

How can I check/get that enum using or passing string? I tried with using Enum.IsDefined(typeof(ActivityEnum), "FMNG") but it is not working with attributes of enum.

Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
k-s
  • 2,192
  • 11
  • 39
  • 73

5 Answers5

1

Here is a generic function:

    public static object ToEnum(string codeToFind, Type t)
    {
        foreach (var enumValue in Enum.GetValues(t))
        {
            CodeAttribute[] codes = (CodeAttribute[])(enumValue.GetType().GetField(enumValue.ToString()).
            GetCustomAttributes(typeof(CodeAttribute), false));

            if (codes.Length > 0 && codes[0].Code.Equals(codeToFind, StringComparison.InvariantCultureIgnoreCase) ||
                enumValue.ToString().Equals(codeToFind, StringComparison.InvariantCultureIgnoreCase))
                return enumValue;
        }

        return null;
    }

Usage: var test = ToEnum("INST_MAST_MGT", typeof(TestEnum));

The above function will return the Enum value if it finds the defined Code attribute or the codeToFind parameter is equal to Enum's value ToString, you can adapt it by your needs.

Novitchi S
  • 3,711
  • 1
  • 31
  • 44
  • 3
    If you made your method generic, it could have the signature `public static T ToEnum(string codeToFind) where T : struct`. Note that if the enum defines several constants with the same numerical value, `Enum.GetValues` is not a good choice. – Jeppe Stig Nielsen May 21 '13 at 10:43
  • The return type is `Object` to be able to return null value if the Code is not found, it seams easier this way. – Novitchi S May 21 '13 at 10:57
  • If you really want that, you can return a nullable `T`, also known as `T?`. Or you could use the try-get pattern: return `bool` and use an `out` variable of type `T` for the result. – Jeppe Stig Nielsen May 21 '13 at 11:01
1

It might also be an idea to do away with the attribute altogether and create a static dictionary for the codes:

static Dictionary<string, TestEnum> codeLookup = new Dictionary<string, TestEnum>() { 
                                                     { "FMNG" , TestEnum.FunctionsManagement }, 
                                                     { "INST_MAST_MGT", TestEnum.MasterInsManagement } };

Then just do

bool isDefined = codeLookup.ContainsKey("FMNG");

This may well be faster than using reflection each time to loop up the attribute, but it depends on your needs

jcharlesworthuk
  • 1,079
  • 8
  • 16
0
public TestEnum GetEnumByAttributeName(string attributeName)
{
    foreach (var item in Enum.GetNames(typeof(TestEnum)))
    {
        var memInfo = typeof(TestEnum).GetMember(item);
        var attributes = memInfo[0].GetCustomAttributes(typeof(CodeAttribute), false);
        if (attributes.Count()> 0 && ((CodeAttribute)attributes[0]).Code == attributeName)
            return (TestEnum)Enum.Parse(typeof(TestEnum), item);
    }
    return TestEnum.None;
}
Damith
  • 62,401
  • 13
  • 102
  • 153
0

You can use this method:

public static T GetEnumValueByAttributeString<T>(string code) where T : struct
{
  if (!typeof(T).IsEnum)
    throw new ArgumentException("T should be an enum");

  var matches = typeof(T).GetFields().Where(f =>
    ((CodeAttribute[])(f.GetCustomAttributes(typeof(CodeAttribute), false))).Any(c => c.Code == code)
    ).ToList();

  if (matches.Count < 1)
    throw new Exception("No match");
  if (matches.Count > 1)
    throw new Exception("More than one match");

  return (T)(matches[0].GetValue(null));
}

Like you see, it checks if the string you come with is ambiguous. Use it like this:

var testEnum = GetEnumValueByAttributeString<TestEnum>("FMNG");

If performance is an issue, you might want to initialize and keep a Dictionary<string, T> of all the "translations", for quick lookup.

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
0

I found generic method below:

public static T GetEnumValueFromDescription<T>(string description)
        {
            var type = typeof(T);
            if (!type.IsEnum)
                throw new ArgumentException();

            FieldInfo[] fields = type.GetFields();
            var field = fields.SelectMany(f => f.GetCustomAttributes(
                                typeof(CodeAttribute), false), (
                                    f, a) => new { Field = f, Att = a })
                            .Where(a => ((CodeAttribute)a.Att)
                                .Code == description).SingleOrDefault();
            return field == null ? default(T) : (T)field.Field.GetRawConstantValue();
        }

Source: Get Enum from Description attribute

Community
  • 1
  • 1
k-s
  • 2,192
  • 11
  • 39
  • 73