【问题标题】:Using C# LINQ Expressions for both Value Types and Reference Types对值类型和引用类型使用 C# LINQ 表达式
【发布时间】:2011-04-18 19:01:18
【问题描述】:

我将 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 将为空)。下面的代码试图只写出 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 时,它似乎仍然认为它正在处理一个对象(DebugView 属性是(System.Object)$p.ID)。

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

这是我使用的类型:

[DataContract(IsReference = true, Namespace = "urn:test:TimeObject")]
public class TimeObject
{
    [DataMember]
    public long ID { get; set; }

    [DataMember]
    public string Content { get; set; }

    [DataMember]
    public DateTime Created { get; set; }
}

【问题讨论】:

  • 这与您的问题无关,但使用自定义 ActionResult 会更好。你甚至可以在这里使用它:notesfor.net/post/2010/06/28/…
  • 你确定值类型是属性吗?也许它们是需要您将其转换为 (FieldInfo) 的字段
  • @Talljoe 这是一个选项,但我不希望使用该解决方案所依赖的魔术字符串(对于忽略的字段)。它似乎也不支持复杂对象(如果 CSVUserModel 上有一个用户,其中包含用户名和密码)。
  • @Slaks @Jose 它不起作用... memberExpression 为空。这是我的 TimeObject 类: [DataContract(IsReference = true, Namespace = "urn:test:TimeObject")] public class TimeObject { [DataMember] public long ID { get;放; } [DataMember] 公共字符串内容 { 获取;放; } [DataMember] public DateTime Created { get;放; } }
  • @Langdon,编写自己的内容非常简单,或者您可以在控制器中构建内容并将其传递给 FileResult(它在 mime 类型、可选文件名等方面做正确的事情)。我不相信 Razor 能很好地处理非 HTML。

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


【解决方案1】:

在表达式引用值类型的情况下,编译器必须对引用进行装箱;它是隐含的。这种复杂性意味着值类型成员表达式的表达式树不仅仅是一个 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 "";
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-16
    • 1970-01-01
    • 1970-01-01
    • 2011-02-12
    • 1970-01-01
    • 2014-05-31
    • 1970-01-01
    相关资源
    最近更新 更多