Home > Enterprise >  How to get "Enums" objects in a class by reflection
How to get "Enums" objects in a class by reflection

Time:11-07

I have this class:

public class user
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public EyeColor EyeColor { get; set; }
}
public enum EyeColor
{
    Brown,
    Black
}

I can use user.GetType().GetProperties(); to get properties and then get values of them.
But for enums is different, all I want to do is: getting Enum index, for example brown is 0 and black is 1 for dynamic search on enum fields.
But I have a generic method to get index and I can't use int enumIndex = (EyeColor)user.EyeColor; because I don't know what kind of enum will be pass to the generic method.

public static IQueryable<T> CreateEqualExpressions<T>(IQueryable<T> query, object model)
{
    var result = query;
    var propertiesToSearch = model.GetType().GetProperties()
        .Where(x => Attribute.IsDefined(x, typeof(EqualSearchAttribute)))
        .ToList();
    if (propertiesToSearch.Count > 0)
    {
        foreach (var propertyInfo in propertiesToSearch)
        {
            var propertyValue = propertyInfo.GetValue(model);
            if (!string.IsNullOrWhiteSpace(propertyValue?.ToString()))
            {
                var parameter = Expression.Parameter(typeof(T));
                var property = Expression.Property(parameter, propertyInfo.Name);
                if (propertyValue is string)
                    propertyValue = propertyValue.ToString()?.Trim();
                var constantValue = Expression.Constant(propertyValue);
                var equal = Expression.Equal(property, constantValue);
                var exp = Expression.Lambda<Func<T, bool>>(equal, parameter);
                result = result.Where(exp);
            }
        }
    }

    return result;
}

Everything is ok for strings but for enums not works because propertyValue is: Brown or Black, but for dynamic search, I need to index of them like 0 or 1. Any suggestion ?

CodePudding user response:

If I understand correctly, you just need Convert.ToInt64 to convert the enum value to a long, which fits every enum underlying type.

var value = propertyInfo.GetValue(model);
if (propertyInfo.PropertyType.IsEnum) {
    long underlyingEnumValue = Convert.ToInt64(value);
    // construct your expression here...
}

Note that if you are constructing an Expression.Equal, with one of the operands being the EyeColor property access, you should convert that to long too:

var equal = Expression.Equal(
    Expression.Convert(property, typeof(long)), 
    Expression.Constant(underlyingEnumValue)
);

Example code:

var prop = typeof(User).GetProperty("EyeColor")!;
var value = prop.GetValue(new User() { EyeColor = EyeColor.Black });
var underlyingEnumValue = Convert.ToInt64(value);

var p = Expression.Parameter(typeof(User));
var lambda = Expression.Lambda(
    Expression.Equal(
        Expression.Convert(
            Expression.Property(p, prop), 
            typeof(long)), Expression.Constant(underlyingEnumValue)
    ), p
);

var del = lambda.Compile();
var result1 = del.DynamicInvoke(new User() { EyeColor = EyeColor.Brown });
var result2 = del.DynamicInvoke(new User() { EyeColor = EyeColor.Black });

Console.WriteLine(result1); // False
Console.WriteLine(result2); // True

CodePudding user response:

What about something like this?

var type = propertyInfo.PropertyType;
if (type.IsEnum)
{
  var enumIndex = (int) propertyValue;
}
  • Related