2011-06-21 106 views
2

我已經重構了使用lambda表達式來訪問正確的價值觀可以在不使用MVC的情況下訪問DisplayName屬性?

public static string ToCsv<TModel>(this List<TModel> list, string delimiter, string lineBreak, string valueWrap, params Expression<Func<TModel, object>>[] expressions) 
{ 
    var sb = new StringBuilder(); 

    var headers = expressions.Select(m => String.Format("{0}{1}{0}", valueWrap, GetPropertyName(m))).ToArray(); 
    sb.Append(String.Format("{0}{1}", String.Join(delimiter, headers), lineBreak)); 

    foreach (var listItem in list) 
    { 
    var values = expressions.Select(m => String.Format("{0}{1}{0}", valueWrap, m.Compile()(listItem))).ToArray(); 
    sb.Append(String.Format("{0}{1}", String.Join(delimiter, values), lineBreak)); 
    } 

    return sb.ToString(); 
} 

這非常適用於列表中的一個通用的CSV建設者,但因爲我想這在多臺服務器轉移到一些常用代碼爲幾個項目訪問。我不能參考System.Web.Mvc程序集

有沒有很好的方法來訪問DisplayName屬性,如果不存在,訪問變量名?

我目前的嘗試訪問((MemberExpression) expression.Body).Member.Name然而,如果它必須將值轉換爲字符串,它將無法正常工作。 (即傳遞一個int和隱式轉換)

遍歷屬性爲內部類沒有工作的第二個嘗試(即model =>model.innerClass.property

+0

更多信息:在沒有解決方案後,我繼續使用'System.Web.Mvc.ExpressionHelper',但是我遇到了另一個問題。沒有HtmlHelper及其ViewData,它將不會獲取屬性的DisplayName屬性。有任何想法嗎? –

回答

0

隨着幾個簡單的輔助功能,可以消除所有參考到System.Web.Mvc程序集。你還會注意到在下面的例子中(model => model.member.property)的作品。

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Linq; 
using System.Linq.Expressions; 
using System.ComponentModel; 
using System.Reflection; 

namespace Test 
{ 
    public class Program 
    { 
     public static void Main(string[] args) 
     { 
      List<Class1> foobars = new List<Class1>(); 
      foobars.Add(new Class1 { Foo = "Hello world!", Bar = -1, Skip = false, Ref = new Class2 { ToBe = true } }); 

      string result = foobars.ToCsv(",", Environment.NewLine, "\"", m => m.Foo, m => m.Bar, m => m.Ref.ToBe); 
     } 

     public class Class1 
     { 
      [DisplayName("Foo Property")] 
      public string Foo { get; set; } 

      public int Bar { get; set; } 

      [DisplayName("Skipped Property")] 
      public bool Skip { get; set; } 

      [DisplayName("Reference")] 
      public Class2 Ref { get; set; } 
     } 

     public class Class2 
     { 
      [DisplayName("To Be or Not To Be")] 
      public bool ToBe { get; set; } 
     } 
    } 

    public static class Extensions 
    { 
     public static string ToCsv<TModel>(this List<TModel> list, string delimiter, string lineBreak, string valueWrap, params Expression<Func<TModel, object>>[] expressions) 
     { 
      var sb = new StringBuilder(); 

      var headers = expressions.Select(m => String.Format("{0}{1}{0}", valueWrap, GetDisplayName(m))).ToArray(); 
      sb.Append(String.Format("{0}{1}", String.Join(delimiter, headers), lineBreak)); 

      foreach (var listItem in list) 
      { 
       var values = expressions.Select(m => String.Format("{0}{1}{0}", valueWrap, m.Compile()(listItem))).ToArray(); 
       sb.Append(String.Format("{0}{1}", String.Join(delimiter, values), lineBreak)); 
      } 

      return sb.ToString(); 
     } 

     // Get DisplayName, otherwise fallback to Name 
     private static string GetDisplayName(LambdaExpression memberReference) 
     { 
      MemberInfo info = GetMemberInfo(memberReference); 
      DisplayNameAttribute displayNameAttr = Attribute.GetCustomAttribute(info, typeof(DisplayNameAttribute)) as DisplayNameAttribute; 
      return (displayNameAttr != null ? displayNameAttr.DisplayName : info.Name); 
     } 

     // Can be swapped for your favourite GetMemberInfo/GetPropertyInfo utility method (there are many out there) 
     // Source: http://blog.baltrinic.com/software-development/dotnet/extension-methods-for-converting-lambda-expression-to-strings 
     private static MemberInfo GetMemberInfo(LambdaExpression memberReference) 
     { 
      MemberExpression memberExpression; 
      var unary = memberReference.Body as UnaryExpression; 
      if (unary != null) 
       //In this case the return type of the property was not object, 
       //so .Net wrapped the expression inside of a unary Convert() 
       //expression that casts it to type object. In this case, the 
       //Operand of the Convert expression has the original expression. 
       memberExpression = unary.Operand as MemberExpression; 
      else 
       //when the property is of type object the body itself is the 
       //correct expression 
       memberExpression = memberReference.Body as MemberExpression; 

      if (memberExpression == null || !(memberExpression.Member is MemberInfo)) 
       throw new ArgumentException("Expression was not of the form 'x => x.member'."); 

      return memberExpression.Member; 
     } 
    } 
} 
+0

非常感謝,我今天會試試這個 –

+0

這很接近,它讓我感覺到了正確的道路! –

相關問題