Использование выражений LINQ для C # как для типов значений, так и для типов ссылок - PullRequest
3 голосов
/ 18 апреля 2011

Я использую 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);
        }
    }
}

Я пытался заменить 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; }
}

1 Ответ

6 голосов
/ 18 апреля 2011

В случае если выражение ссылается на тип значения, компилятор должен поместить ссылку в ссылку;это делает это неявно.Это усложнение означает, что дерево выражений для выражения-члена Value Type не просто MemberExpression, поэтому ваше приведение возвращает нуль.

Ниже приведено общее решение для получения имени свойства из Value Type или Reference Type.выражение члена, взятое из этого вопроса :

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