对值类型和引用类型使用 C# LINQ 表达式
我使用 MVC 进行 REST,以便可以利用 Razor 输出不同类型。 CSV 是这些输出之一。我不想为每种输入类型编写此模板:
ID,Created,Content
@foreach (var item in Model.TimeData)
{
<text>@item.ID,@item.Created,"@Html.Raw(item.Content.Replace("\"", "\"\""))"</text>
}
我想利用 params
和 System.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 是值类型(int
和 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);
}
}
}
我尝试用 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果表达式引用值类型,编译器必须对引用进行装箱;它是隐含地这样做的。这种复杂性意味着值类型成员表达式的表达式树不仅仅是一个 MemberExpression,因此您的转换将返回 null。
以下是从值类型或引用类型成员表达式获取属性名称的通用解决方案,取自 这个问题:
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: