代码之家  ›  专栏  ›  技术社区  ›  Chris Kooken

在C中,将匿名类型转换为键/值数组?

  •  73
  • Chris Kooken  · 技术社区  · 15 年前

    我有以下匿名类型:

    new {data1 = "test1", data2 = "sam", data3 = "bob"}
    

    我需要一个方法来接受它,并在数组或字典中输出键值对。

    我的目标是将其用作httpRequest中的post数据,以便最终将其连接到以下字符串中:

    "data1=test1&data2=sam&data3=bob"
    
    8 回复  |  直到 7 年前
        1
  •  110
  •   kbrimington    15 年前

    这只需要一点点思考就可以完成。

    var a = new { data1 = "test1", data2 = "sam", data3 = "bob" };
    var type = a.GetType();
    var props = type.GetProperties();
    var pairs = props.Select(x => x.Name + "=" + x.GetValue(a, null)).ToArray();
    var result = string.Join("&", pairs);
    
        2
  •  61
  •   GWB    15 年前

    如果使用.NET 3.5 SP1或.NET 4,则可以(AB)使用 RouteValueDictionary 为此。它实现 IDictionary<string, object> 并且有一个接受 object 并将属性转换为键值对。

    然后,通过循环键和值来构建查询字符串就很简单了。

        3
  •  25
  •   Joh    15 年前

    以下是他们在RouteValueDictionary中的做法:

      private void AddValues(object values)
        {
            if (values != null)
            {
                foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(values))
                {
                    object obj2 = descriptor.GetValue(values);
                    this.Add(descriptor.Name, obj2);
                }
            }
        }
    

    完整来源如下: http://pastebin.com/c1gQpBMG

        4
  •  1
  •   Andiih    15 年前

    @Kbrimington的解决方案是一个很好的扩展方法-我的案例返回了一个htmlstring

        public static System.Web.HtmlString ToHTMLAttributeString(this Object attributes)
        {
            var props = attributes.GetType().GetProperties();
            var pairs = props.Select(x => string.Format(@"{0}=""{1}""",x.Name,x.GetValue(attributes, null))).ToArray();
            return new HtmlString(string.Join(" ", pairs));
        }
    

    我使用它将任意属性放到Razor MVC视图中。我从使用routeValueDictionary和循环结果的代码开始,但这要整洁得多。

        5
  •  1
  •   Jordan    11 年前

    我做了这样的事:

    public class ObjectDictionary : Dictionary<string, object>
    {
        /// <summary>
        /// Construct.
        /// </summary>
        /// <param name="a_source">Source object.</param>
        public ObjectDictionary(object a_source)
            : base(ParseObject(a_source))
        {
    
        }
    
        /// <summary>
        /// Create a dictionary from the given object (<paramref name="a_source"/>).
        /// </summary>
        /// <param name="a_source">Source object.</param>
        /// <returns>Created dictionary.</returns>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="a_source"/> is null.</exception>
        private static IDictionary<String, Object> ParseObject(object a_source)
        {
            #region Argument Validation
    
            if (a_source == null)
                throw new ArgumentNullException("a_source");
    
            #endregion
    
            var type = a_source.GetType();
            var props = type.GetProperties();
    
            return props.ToDictionary(x => x.Name, x => x.GetValue(a_source, null));
        }
    }
    
        6
  •  1
  •   Extragorey    8 年前

    基于@gwb关于使用 RouteValueDictionary ,我编写了这个递归函数来支持嵌套的匿名类型,并通过父类的键对这些嵌套参数进行前缀。

    public static string EncodeHtmlRequestBody(object data, string parent = null) {
        var keyValuePairs = new List<string>();
        var dict = new RouteValueDictionary(data);
    
        foreach (var pair in dict) {
            string key = parent == null ? pair.Key : parent + "." + pair.Key;
            var type = pair.Value.GetType();
            if (type.IsPrimitive || type == typeof(decimal) || type == typeof(string)) {
                keyValuePairs.Add(key + "=" + Uri.EscapeDataString((string)pair.Value).Replace("%20", "+"));
            } else {
                keyValuePairs.Add(EncodeHtmlRequestBody(pair.Value, key));
            }
        }
    
        return String.Join("&", keyValuePairs);
    }
    

    示例用法:

    var data = new {
        apiOperation = "AUTHORIZE",
        order = new {
            id = "order123",
            amount = "101.00",
            currency = "AUD"
        },
        transaction = new {
            id = "transaction123"
        },
        sourceOfFunds = new {
            type = "CARD",
            provided = new {
                card = new {
                    expiry = new {
                        month = "1",
                        year = "20"
                    },
                    nameOnCard = "John Smith",
                    number = "4444333322221111",
                    securityCode = "123"
                }
            }
        }
    };
    
    string encodedData = EncodeHtmlRequestBody(data);
    

    encodedData 变成:

    "apiOperation=AUTHORIZE&order.id=order123&order.amount=101.00&order.currency=AUD&transaction.id=transaction123&sourceOfFunds.type=CARD&sourceOfFunds.provided.card.expiry.month=1&sourceOfFunds.provided.card.expiry.year=20&sourceOfFunds.provided.card.nameOnCard=John+Smith&sourceOfFunds.provided.card.number=4444333322221111&sourceOfFunds.provided.card.securityCode=123"

    希望这能帮助处于类似情况的其他人。

    编辑: 正如Drewg指出的,这不支持数组。要正确地实现对具有匿名类型的任意嵌套数组的支持是非常重要的,因为我使用的所有API都没有接受数组(我甚至不确定是否有标准化的方法用表单编码对它们进行序列化),如果需要支持的话,我将把它留给大家。

        7
  •  1
  •   Xymanek Tomas Jansson    7 年前

    有一种将匿名对象转换为字典的内置方法:

    HtmlHelper.AnonymousObjectToHtmlAttributes(yourObj)
    

    它还会回来 RouteValueDictionary . 注意它是静态的

        8
  •  0
  •   Konstantin Salavatov    8 年前
    using Newtonsoft.Json;
    var data = new {data1 = "test1", data2 = "sam", data3 = "bob"};
    var encodedData = new FormUrlEncodedContent(JsonConvert.DeserializeObject<Dictionary<string, string>>(JsonConvert.SerializeObject(data))
    
    推荐文章