使用表达式获取C#中的智能支持

时间:2018-11-09 20:09:58

标签: c# .net expression

我正在尝试使用表达式,以便对属性进行强类型化。

所以我有这个模型。

public class Entity
{
    public int Id { get; set; }
    public string Name { get; set; }
}

这个方法最终应该以某种方式使用属性,但现在我只想返回它们。

public List<string> DoSomething<TEntity>(params Expression<Func<TEntity, object>>[] expressions)
{  
        List<string> props = new List<string>();

        foreach (var expression in expressions)
        {
            var memberExpression = expression.Body as MemberExpression;

            var q = memberExpression.Member.Name;

            props.Add(q);
        }
        return props;
}

这是用法

var props = DoSomething<Entity>(x => x.Id, x => x.Name);

嗯,它有效,但仅部分起作用。我的意思是,它将适用于引用类型,例如,它将适用于Name属性,因为它是引用类型,但是它将为任何值类型返回null,在这种情况下,它返回的是ID(即int)。

那是为什么?解决方案是什么?

1 个答案:

答案 0 :(得分:3)

Expression<Func<TEntity, object>>是一个表达式,它构建一个函数,该函数返回一个object(它是引用类型)。 如果将x => x.Id作为该Expression的值传递,则由于int是值类型,但Func希望返回引用类型,因此所得Func的返回类型将不匹配。

C#的编译器会看到这一点,并自动构建一个将int包裹在object内的Func(称为装箱)。但是该Func不再具有简单的MemberExpression作为其主体,因为MemberExpression必须包装在“装箱表达式”中。

基本上就是这样。因此,您必须解决expression.Body不是MemberExpression类型的情况来解决此问题。

这未经测试,但可能会有所帮助:

if (!(expression.Body is MemberExpression))
{
    if (expression.Body is UnaryExpression unaryExpression && unaryExpression.NodeType == ExpressionType.TypeAs)
        expression = unaryExpression.Operand as MemberExpression;
    else
        expression = null;
    if (expression == null)
        throw new ArgumentException("something happened");
}