将C#LINQ表达式用于值类型和引用类型

时间:2011-04-18 19:01:19

标签: c# linq generics dynamic c#-4.0

我正在使用MVC进行REST,以便我可以利用Razor输出不同类型。 CSV是这些输出之一。而不是为每种输入类型编写此模板:

ID,Created,Content
@foreach (var item in Model.TimeData)
{
<text>@item.ID,@item.Created,"@Html.Raw(item.Content.Replace("\"", "\"\""))"</text>
}

我想利用paramsSystem.Linq.Expressions.Expression写下这样的内容:

@{
    Html.WriteCsv<TimeObject>(Model.TimeData, p => p.ID, p => p.Created, p => p.Content);   
}

我开始编写泛型HtmlHelper并很快意识到我遇到了值类型的问题(memberExpression将为null)。下面的代码尝试只写出CSV标题(ID,Created,Content),但它只输出“Content”(因为ID和Created是值类型(intDateTime)。

public static void WriteCsv<TModel>(this HtmlHelper htmlHelper, List<TModel> list, params Expression<Func<TModel, object>>[] expressions)
{
    foreach (var expression in expressions)
    {
        MemberExpression memberExpression = expression.Body as MemberExpression;

        if (memberExpression != null)
        {
            var propertyInfo = (PropertyInfo)memberExpression.Member;

            htmlHelper.ViewContext.Writer.Write(propertyInfo.Name + Environment.NewLine);
        }
    }
}

我尝试将object替换为dynamic,认为这样可行,但当我快速观察expression.Body时,它仍然认为它正在处理一个对象({{1} } property是DebugView)。

这在C#4.0中是不可能的吗?

这是我正在使用它的类型:

(System.Object)$p.ID

1 个答案:

答案 0 :(得分:6)

在表达式引用值类型的情况下,编译器必须对引用进行包装;它含蓄地这样做。这种复杂性意味着Value Type成员表达式的表达式树不仅仅是一个MemberExpression,因此您的强制转换返回null。

以下是从this question获取的值类型或引用类型成员表达式中获取属性名称的一般解决方案:

private string GetPropertyName(Expression<Func<object, object>> f) {
    var body = f.Body;
    if (body.NodeType==ExpressionType.Convert)
      body = ((UnaryExpression) body).Operand;
    if ((body as MemberExpression) != null) {
        return (body as MemberExpression).Member.Name;
    }
    return "";
}