对值类型和引用类型使用 C# LINQ 表达式

发布于 2024-11-02 16:55:33 字数 1759 浏览 0 评论 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);
        }
    }
}

我尝试用 dynamic 替换 object,认为这可行,但当我快速观察 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; }
}

I'm using MVC for REST so that I can take advantage of Razor for outputting different types. CSV is one of those outputs. Instead of writing this template for each input type:

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

I wanted to make use of params and System.Linq.Expressions.Expression to write something like this:

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

I started writing a generic HtmlHelper and quickly realized I had problems with value types (memberExpression will be null). The code below attempts to just write out the CSV heading (ID,Created,Content), but it only outputs "Content" (because ID and Created are value types (int and DateTime).

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);
        }
    }
}

I tried replacing object with dynamic, thinking that would work, but when I quick watch expression.Body, it still seems to think it's dealing with an object (the DebugView property is (System.Object)$p.ID).

Is this impossible in C# 4.0?

Here's the type I'm using it on:

[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; }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

蘑菇王子 2024-11-09 16:55:33

如果表达式引用值类型,编译器必须对引用进行装箱;它是隐含地这样做的。这种复杂性意味着值类型成员表达式的表达式树不仅仅是一个 MemberExpression,因此您的转换将返回 null。

以下是从值类型或引用类型成员表达式获取属性名称的通用解决方案,取自 这个问题

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 "";
}

In the case that the expression references a value type, the compiler has to box the reference; it does so implicitly. This complication means that the expression tree for a Value Type member expression is not simply a MemberExpression, so your cast is returning null.

The following is a general solution for obtaining the property name from a Value Type or Reference Type member expression, taken from 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 "";
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文