【问题标题】:C# downcast the object type to mapC#向下转换对象类型以映射
【发布时间】:2015-03-11 14:52:33
【问题描述】:

我使用JavaScriptSerializer将一个json字符串序列化为一个特定的类

这里是原始 json 字符串:

{
   "status":0,
   "data":[
          {
             "username":"yong6180212856@163.com",
             "password":"r2166745"
          }, 
          {
             "username":"xinnai1122139@163.com",
             "password":"f0341303"
          }
          ],
   "msg":"OK"
}

这是来自 http 服务器的结构化响应,data 字段会因不同的请求而有所不同。所以在RetData 类中,我不想制作一个固定类型的data,只使用Object,然后在需要时向下转换为相应的类型。

 class RetData {
    public int status {get;set;}
    public string msg {get;set;}
    public List<Object> data {get;set;}
 }

使用后

 RetData retData = new JavaScriptSerializer<RetData>(jsonStr);

然后我想像这样检索每个密码:

foreach (var item in retData.data){
   // some thing like this but I really don't know which type 
   // should I downcast to here.
   //                  |
   //                  V
   string password = ((??map??)item).getString("password"); 
   Console.WriteLine(password);
}

如您所见,我应该向下转换为什么类型,以检索 password 飞行,我对 Java 有点熟悉,但是 C# 的新手,需要一些帮助。

【问题讨论】:

  • 你不能用 List 做到这一点。尝试改用 JObject 或动态。

标签: c# json


【解决方案1】:

这里有很多方法。您所在位置的最短路径是将 RetData 更改为:

public class RetData
{
    public int status { get; set; }
    public string msg { get; set; }
    public List<Dictionary<object,object>> data { get; set; }
}

然后像这样读取数据:

RetData retData = (RetData)new JavaScriptSerializer().Deserialize(jsonStr, typeof(RetData));

foreach (var item in retData.data)
{
    string password = item["username"].ToString();
    Console.WriteLine(password);
}

限制是这实际上只适用于简单的名称/值对。另一种方法是更改​​为使用 Newtonsoft Json,而不是 Microsoft Json。这有一种称为“JObject”的类型,可以真正处理任何类型的 Json 数据。 Newtonsoft Json 以 nuget 包的形式提供。

我对动态的评论是错误的。我试过了,结果发现.NET 序列化程序不理解动态或 ExpandoObject。 :-(

【讨论】:

    【解决方案2】:

    当您将带有 JavaScriptSerializer 的 JSON 反序列化为 object 属性或字段时,序列化程序将递归地选择最合适的表示形式来反序列化其中的每个 JSON 元素:

    这允许反序列化和使用完全通用的 JSON 数据。

    一些有助于处理来自JavaScriptSerializer 的无类型反序列化 JSON 的扩展方法包括:

    public static class JavaScriptSerializerObjectExtensions
    {
        public static object JsonElementAt(this object obj, int index)
        {
            if (index < 0)
                throw new ArgumentException();
            var array = obj as object[];
            if (array == null || index >= array.Length)
                return null;
            return array[index];
        }
    
        public static object JsonPropertyAt(this object obj, string name)
        {
            var dict = obj as IDictionary<string, object>;
            if (dict == null)
                return null;
            object value;
            if (!dict.TryGetValue(name, out value))
                return null;
            return value;
        }
    
        public static bool IsJsonArray(this object obj)
        {
            return obj is object[];
        }
    
        public static object [] AsJsonArray(this object obj)
        {
            return obj as object[];
        }
    
        public static bool IsJsonObject(this object obj)
        {
            return obj is IDictionary<string, object>;
        }
    
        public static IDictionary<string, object> AsJsonObject(this object obj)
        {
            return obj as IDictionary<string, object>;
        }
    
        public static bool IsJsonNumber(this object obj)
        {
            if (obj == null)
                return false;
            switch (Type.GetTypeCode(obj.GetType()))
            {
                case TypeCode.Int32:
                case TypeCode.Int64:
                case TypeCode.Decimal:
                case TypeCode.Double:
                    return true;
    
                case TypeCode.Byte:
                case TypeCode.SByte:
                case TypeCode.UInt16:
                case TypeCode.UInt32:
                case TypeCode.UInt64:
                case TypeCode.Int16:
                case TypeCode.Single:
                    Debug.WriteLine("Unexpected integer type " + Type.GetTypeCode(obj.GetType()));
                    return true;
    
                default:
                    return false;
            }
        }
    
        public static bool IsJsonBoolean(this object obj)
        {
            return obj is bool;
        }
    
        public static bool IsJsonString(this object obj)
        {
            return obj is string;
        }
    
        public static bool IsDateTime(this object obj)
        {
            return obj is DateTime;
        }
    
        [Conditional("DEBUG")]
        public static void DebugWriteJson(this object obj)
        {
            var sb = obj.DumpJson();
            Debug.WriteLine(sb);
        }
    
        public static string DumpJson(this object obj)
        {
            var sb = obj.DumpJson(new StringBuilder(), 0, false, string.Empty);
            return sb.ToString();
        }
    
        static StringBuilder DumpJson(this object obj, StringBuilder sb, int level, bool isPropertyValue, string postfix)
        {
            if (obj == null)
                return sb;
            string prefix = new string(' ', 2 * level);
            if (obj is IList<object>)
            {
                var array = (IList<object>)obj;
                if (isPropertyValue)
                    sb.AppendLine();
                sb.AppendLine(prefix + "[");
                for (int i = 0; i < array.Count; i++)
                {
                    array[i].DumpJson(sb, level + 1, false, (i == array.Count - 1 ? string.Empty : ","));
                }
                sb.AppendLine(prefix + "]" + postfix);
            }
            else if (obj is IDictionary<string, object>)
            {
                if (isPropertyValue)
                    sb.AppendLine();
                sb.AppendLine(prefix + "{");
                var dict = ((IDictionary<string, object>)obj).ToList();
                for (int i = 0; i < dict.Count; i++)
                {
                    sb.AppendFormat("{0}  \"{1}\" : ", prefix, dict[i].Key);
                    dict[i].Value.DumpJson(sb, level + 2, true, (i == dict.Count - 1 ? string.Empty : ","));
                }
                sb.AppendLine(prefix + "}" + postfix);
            }
            else if (obj.IsJsonString())
            {
                string initialPrefix = (isPropertyValue ? "" : prefix);
                sb.AppendLine(initialPrefix + '"' + obj.ToString() + '"' + postfix);
            }
            else
            {
                string initialPrefix = (isPropertyValue ? "" : prefix);
                sb.AppendLine(initialPrefix + obj.ToString().ToLower() + postfix);
            }
            return sb;
        }
    

    然后你可以这样做:

    class RetData
    {
        public int status { get; set; }
        public string msg { get; set; }
        public object data { get; set; }
    }
    
            var retData = (new JavaScriptSerializer()).Deserialize<RetData>(jsonStr);
    
            if (retData.data.IsJsonArray())
                foreach (var obj in retData.data.AsJsonArray())
                    if (obj.JsonPropertyAt("username") != null)
                        Console.WriteLine(obj.JsonPropertyAt("password"));
    

    或者,如果它看起来更熟悉:

            if (retData.data.IsJsonArray())
                foreach (var obj in retData.data.AsJsonArray())
                    if (obj.IsJsonObject())
                    {
                        var map = obj.AsJsonObject();
                        if (map.ContainsKey("username") && map.ContainsKey("password"))
                            Console.WriteLine(map["password"]);
                    }
    

    不过,老实说,这接近于重新发明 Linq-to-Json,因此您可能想研究一下切换到 Json.NET

    【讨论】:

      【解决方案3】:

      使用dynamic关键字定义data的类型:

      class RetData
      {
          public int status { get; set; }
          public string msg { get; set; }
          public dynamic data { get; set; }
      }
      

      请注意,这将取消智能感知和编译验证,这意味着检查类型的责任是你的。

      或者,通过更多关于您的设计的细节,您可能能够创建一个基础数据类,而不是为您的不同数据类型继承和实现它。

      【讨论】:

      • 谢谢,我会试试的,你能更具体地谈谈创建一个基础数据类吗?我不太明白。
      • 正如我所说,需要更多细节。但只是为了激发您的想象力: - 创建一个抽象类(我们称之为 MyData) - 创建一个抽象属性或方法“GetPassword” - 继承该类并以不同的方式实现 GetPassword
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-24
      • 1970-01-01
      • 1970-01-01
      • 2013-01-10
      相关资源
      最近更新 更多