【问题标题】:Is there an easy way to convert object properties to a dictionary<string, string>有没有一种简单的方法可以将对象属性转换为字典<string, string>
【发布时间】:2012-02-25 06:56:54
【问题描述】:

我有一个数据库对象(一行),它有很多属性(列)映射到表单字段(asp:textbox、asp:dropdownlist 等)。我想将此对象和属性转换为字典映射,以使其更易于迭代。

例子:

Dictionary<string, string> FD = new Dictionary<string,string>();
FD["name"] = data.name;
FD["age"] = data.age;
FD["occupation"] = data.occupation;
FD["email"] = data.email;
..........

在不手动输入所有不同的 100 种属性的情况下,我如何轻松做到这一点?

注意:FD 字典索引与数据库列名相同。

【问题讨论】:

    标签: c# asp.net dictionary reflection


    【解决方案1】:

    假设data 是某个对象,并且您想将其公共属性放入字典中,那么您可以尝试:

    原创 - 出于历史原因(2012 年)

    Dictionary<string, string> FD = (from x in data.GetType().GetProperties() select x)
        .ToDictionary (x => x.Name, x => (x.GetGetMethod().Invoke (data, null) == null ? "" : x.GetGetMethod().Invoke (data, null).ToString()));
    

    更新(2017 年)

    Dictionary<string, string> dictionary = data.GetType().GetProperties()
        .ToDictionary(x => x.Name, x => x.GetValue(data)?.ToString() ?? "");
    

    【讨论】:

    • 它比硬编码等值更快吗?我们可以逆转这个过程,将 FD 字典变回字符串对象吗?我会对此进行一些测试。
    • 您的代码有语法错误 CS1922:无法使用集合初始化程序初始化类型“System.Collections.Generic.KeyValuePair”,因为它没有实现“System” .Collections.IEnumerable'
    • @Dexter 已更正 - 使用 { 而不是 (。请再试一次。
    • 另一个错误说 ToDictionary 不能接受零参数。我认为它需要将 KeyValuePair 作为参数或其他东西。
    • 是的 --woah wtf... 你的算法刚刚从 2900 万纳秒到 200 万纳秒。它适用于空值!最佳答案归您所有。
    【解决方案2】:

    HtmlHelper 类允许将 Anonymouns 对象转换为 RouteValueDictonary,我想您可以在每个值上使用 .ToString() 来获取字符串表示:

     var linkAttributes = System.Web.Mvc.HtmlHelper.AnonymousObjectToHtmlAttributes(linkHtmlAttributes);
    

    缺点是这是 ASP.NET MVC 框架的一部分。使用.NET Reflector,方法内部代码如下:

    public static RouteValueDictionary AnonymousObjectToHtmlAttributes(object htmlAttributes)
    {
       RouteValueDictionary dictionary = new RouteValueDictionary();
      if (htmlAttributes != null)
      {
         foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(htmlAttributes))
         {
                dictionary.Add(descriptor.Name.Replace('_', '-'), descriptor.GetValue(htmlAttributes));
           }
     }
        return dictionary;
     }
    

    你会看到这段代码和 Yahia 给你的答案是一样的,他的答案提供了一个字典。使用我给您的反映代码,您可以轻松地将 RouteValueDictionary 转换为 Dictonary 但 Yahia 的答案是单行。

    编辑 - 我已经添加了代码,说明什么可能是进行转换的方法:

    编辑 2 - 我在代码中添加了 null 检查并使用 String.Format 作为字符串值

        public static Dictionary<string, string> ObjectToDictionary(object value)
        {
            Dictionary<string, string> dictionary = new Dictionary<string, string>();
            if (value != null)
            {
                foreach (System.ComponentModel.PropertyDescriptor descriptor in System.ComponentModel.TypeDescriptor.GetProperties(value))
                {
                    if(descriptor != null && descriptor.Name != null)
                    {
                         object propValue = descriptor.GetValue(value);
                         if(propValue != null)
                              dictionary.Add(descriptor.Name,String.Format("{0}",propValue));
                }
            }
            return dictionary;
        }
    

    并从字典转到对象检查 http://automapper.org/,这是在此线程中建议的 Convert dictionary to anonymous object

    【讨论】:

    • 我不使用 MVC,我正在将数据对象转换为字典而不是处理 html。
    • @Dexter 您可能没有使用 MVC,但我给了您“AnonymousObjectToHtmlAttributes”方法的代码,以了解它的作用。我不确定您所说的处理 HTML 是什么意思。如果您指的是“HtmlHelper”命名空间,那就是它,一些方法的命名空间容器。我还给你写了一个与它相同的方法的例子,它可以返回一个字典。
    • 好的,我正在测试您的代码,但我认为 descripter 有时可能为空。所以我添加了一个 if(descriptor != null) 和 if(descripter.GetValue(value) != null)
    • GetProperties 不应返回 null,否则我们的所有示例都将在每个人都使用它时被破坏。 descriptor.GetValue(value) 可以返回 null,因此使用 String.Format("{0}",descriptor.GetValue(value)) 会更好,那么值将是“”。如果您想省略值为“”的字段,那么请务必先检查该值。
    • 好吧,我无法用空值测试你的代码。它一直给我错误。所以我只是创建了一个包含所有字段值的数据库行。但是,很好的答案。你的算法在速度/效率测试中排名第二(上图),只用了 700 万纳秒。
    【解决方案3】:
    var myDict = myObj.ToDictionary(); //returns all public fields & properties
    

    .

    public static class MyExtensions
    {
        public static Dictionary<string, object> ToDictionary(this object myObj)
        {
            return myObj.GetType()
                .GetProperties()
                .Select(pi => new { Name = pi.Name, Value = pi.GetValue(myObj, null) })
                .Union( 
                    myObj.GetType()
                    .GetFields()
                    .Select(fi => new { Name = fi.Name, Value = fi.GetValue(myObj) })
                 )
                .ToDictionary(ks => ks.Name, vs => vs.Value);
        }
    }
    

    【讨论】:

    • Highlighting .Select(pi => new { Name = pi.Name, Value = pi.GetValue(myObj, null).ToString() }) --- 对象未设置为引用。我添加了 ToString,因为我想要 Dictionary 而不是 。但是如果数据库字段为空/null,则该对象未设置为引用问题。
    • 此处最快算法获胜者。抱歉,我无法决定谁的答案最好。他们都是很好的答案。第一种算法(Splash-X):7,000,700 纳秒0.01 秒0.00 分钟第二种算法(LB):3,000,300 纳秒 0.00 秒0.00 分钟第三个算法(Yahia):29,002,900 纳秒0.03 秒0.00 分钟
    • 供您参考---当数据库具有 NULL 值时,此代码也会中断。
    • 实际上 Yahia 编辑了他提交的算法,现在它的运行速度比你的快 100 万纳秒。
    【解决方案4】:

    看看System.ComponentModel.TypeDescriptor.GetProperties( ... )。这是正常数据绑定位的工作方式。它将使用反射并返回一组属性描述符(您可以使用它来获取值)。您可以通过实现 ICustomTypeDescriptor 来自定义这些描述符以获得性能。

    【讨论】:

      猜你喜欢
      • 2011-01-19
      • 2019-10-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-09-24
      • 2010-09-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多