检查表达式树中的枚举属性

时间:2014-09-29 13:15:16

标签: c# enums lambda expression-trees

我有一个带有标记项目的自定义属性的枚举:

enum MyColourEnum {        
    [RenderAs("'#ff0000'")]
    Red,

    [RenderAs("'#00ff00'")]
    Green
}

然后我创建一个使用枚举的表达式树:

Expression<Func<Environment,bool>> expr = _ => _.Colour == MyColourEnum.Red;

然后我解析表达式树并将其转换为表达式的字符串表示形式。我想要的结果字符串是:

"environment.colour == '#ff0000'"

我遇到的问题是enum值变为lambda中的常量,所以当查看表达式树时,它会看到常量值0而不是读取枚举的Red项的表达式

我想使用自定义属性将枚举标识为特殊情况,并将其替换为附加到属性的值,但我不能因为我能看到的只是常量0值。

如何获取用于在表达式树中创建常量的枚举?

如果你不能,那么我怎么能做类似的事呢?

2 个答案:

答案 0 :(得分:2)

对于特定示例,以下代码可用。

Expression<Func<Environment,bool>> expr = _ => _.Colour == MyColourEnum.Red;
BinaryExpression binaryExpression = (BinaryExpression)expr.Body;

var convert = (UnaryExpression)binaryExpression.Left;
var propertyExpression = (MemberExpression)convert.Operand;
var property = (PropertyInfo)propertyExpression.Member;

Enum enumValue = (Enum)Enum.ToObject(property.PropertyType, ((ConstantExpression)binaryExpression.Right).Value); //
FieldInfo fi = property.PropertyType.GetField(enumValue.ToString());
var renderAs = fi.GetCustomAttribute<RenderAsAttribute>();

if (renderAs != null)
{
    String color = renderAs.Color;

    Console.WriteLine("{0}.{1} == {2}", property.DeclaringType.Name, property.Name, color);
}

目前,我已对==运算符进行了硬编码,如果您想让它变为动态,则需要检查binaryExpression.NodeType属性。

注意:当您的枚举具有重复值时,这将无法正常工作。 (即e)具有相同值的多个枚举字段。上述代码没有问题,Enum.ToObject在找到重复时会被破坏。事实上,当你有重复项时,枚举中的大多数方法都无法正常工作。

答案 1 :(得分:1)

Enum类型不是为了那个!使用Enum的自定义用户属性是错误的,这是开发方式。最后它总是成为一些难以支持的怪物。 你最好创建一些抽象类:

public abstract class DescriptedCodeValue
{
    protected DescriptedCodeValue(int id, string description)
    {
        Id = id;
        Description = description;
    }
    public int Id { get; private set; }
    public string Description { get; private set; }

    public static implicit operator int(DescriptedCodeValue val)
    {
        return val.Id;
    }

    public static implicit operator string(DescriptedCodeValue val)
    {
        return val.Description;
    }

    public override string ToString()
    {
        return Description;
    }
}

之后你只需继承它,例如:

public class ColorCode : DescriptedCodeValue
{
    private ColorCode(int id, string description) : base(id, description) { }
    public static ColorCode Red = new ColorCode(1, "#ff0000");
    public static ColorCode Green = new ColorCode(2, "#00ff00");
}

最后,它只是一个例子。您可以根据需要轻松优化该类,主要的好处是您可以轻松地在任何地方扩展功能而无需对项目进行重大更改。