c# - 是否可以在不使用 MVC 的情况下访问 DisplayName 属性?

标签 c# asp.net-mvc linq reflection extension-methods

我已经使用 lambda 表达式重构了 List 的通用 CSV 构建器以访问正确的值

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

这很好用,但是因为我正试图将它移动到一些通用代码中,供跨多个服务器的多个项目访问。我无法引用 System.Web.Mvc 程序集

是否有访问 DisplayName 属性的好方法,如果不存在,则访问变量名称?

我当前尝试访问 ((MemberExpression) expression.Body).Member.Name 但是,如果它必须将值转换为字符串,它将无法工作。 (即传递一个 int 并隐式转换)

迭代属性的第二次尝试对内部类不起作用(即 model => model.innerClass.property)

最佳答案

通过几个简单的辅助函数,您可以消除对 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;
        }
    }
}

关于c# - 是否可以在不使用 MVC 的情况下访问 DisplayName 属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6427034/

相关文章:

javascript - 图像、JS 文件未在 MVC 应用程序中加载

c# - YouTube API登录用户缩略图C#

c# - 迭代并返回连续 n 个元素的数组

c# - 使用 LINQ/Lambdas 将 String[] 复制到 List<String> 中?

C# 从线程访问类成员

c# - MVC 中的 AJAX JSON 调用来过滤 View 中的列表

c# - 从另一个 VR Oculus 应用启动 VR Oculus 应用

c# - 从 SQL 查询 c# 创建树/XML 结构

c# - ASP.NET MVC4 一 View 多模型

c# - LINQ:为什么我不能在返回的对象中声明新对象?