[英]Deserializing a JSON object hierarchy into a hierarchy of Dictionary<string, object>
[英]Converting hierarchy of Dictionary<string, object> to nested class
我有一個基礎班,有一系列作為公共成員的班。 我正在嘗試將Dictionary轉換為此類。
任何想法如何擺脫這個例外? 當基類包含基本類型而不是我創建的類型(或我創建的類型列表)時,此代碼似乎很棒。
異常輸出:
================================================================================
= Exception Type: System.InvalidCastException
= Exception Dat System.Collections.ListDictionaryInternal
= Inner Exception:
= Exception Message: Object must implement IConvertible.
= Exception Source: mscorlib
= Exception StackTrace: at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
at System.Convert.ChangeType(Object value, Type conversionType)
at sandbox.Program.DictToObject[T](IDictionary`2 dict) in D:\Code\Misc\Sandbox\sandbox\Program.cs:line 91
at sandbox.Program.Main(String[] args) in D:\Code\Misc\Sandbox\sandbox\Program.cs:line 48
================================================================================
碼:
using System;
using System.Collections.Generic;
using System.Reflection;
namespace sandbox
{
public class BaseClass
{
public int SomeInt { get; set; }
public string SomeString { get; set; }
public SubClass ScSingleton { get; set; }
public List<SubClass> ScList { get; set; }
}
public class SubClass
{
public int AnotherInt { get; set; }
public string AnotherString { get; set; }
}
public partial class Program
{
static void Main(string[] args)
{
try
{
Dictionary<string, object> outer = new Dictionary<string, object>();
outer.Add("SomeInt", 5);
outer.Add("SomeString", "foo");
Dictionary<string, object> scSingle = new Dictionary<string, object>();
scSingle.Add("AnotherInt", 10);
scSingle.Add("AnotherString", "bar");
outer.Add("ScSingleton", scSingle);
List<Dictionary<string, object>> scList = new List<Dictionary<string, object>>();
scList.Add(scSingle);
outer.Add("ScList", scList);
BaseClass b = DictToObject<BaseClass>(outer);
}
catch (Exception e)
{
PrintException(e);
}
finally
{
Console.WriteLine("");
Console.Write("Press ENTER to exit.");
Console.ReadLine();
}
return;
}
public static T DictToObject<T>(IDictionary<string, object> dict) where T : new()
{
T t = new T();
PropertyInfo[] properties = t.GetType().GetProperties();
foreach (KeyValuePair<string, object> curr in dict)
{
if (String.IsNullOrEmpty(curr.Key)) continue;
if (curr.Value == null) continue;
Type valType = null;
Type newType = null;
PropertyInfo currProperty = null;
foreach (PropertyInfo p in properties)
{
if (String.IsNullOrEmpty(p.Name)) continue;
if (String.Compare(p.Name.ToLower(), curr.Key.ToLower()) == 0)
{
valType = t.GetType().GetProperty(p.Name).PropertyType;
newType = Nullable.GetUnderlyingType(valType) ?? valType;
currProperty = p;
break;
}
}
object newVal = Convert.ChangeType(curr.Value, newType);
t.GetType().GetProperty(currProperty.Name).SetValue(t, newVal);
}
return t;
}
static void PrintException(Exception e)
{
Console.WriteLine("================================================================================");
Console.WriteLine(" = Exception Type: " + e.GetType().ToString());
Console.WriteLine(" = Exception Dat " + e.Data);
Console.WriteLine(" = Inner Exception: " + e.InnerException);
Console.WriteLine(" = Exception Message: " + e.Message);
Console.WriteLine(" = Exception Source: " + e.Source);
Console.WriteLine(" = Exception StackTrace: " + e.StackTrace);
Console.WriteLine("================================================================================");
}
}
}
如果您堅持走黑色反射魔術之路,則可以使用以下方法來完成您想要的東西(丑陋且效率低下,可以美化和優化):
interface ICollectionBuilder
{
object Build(IList dictionaries);
}
interface IDictionaryConverter
{
object Convert(IDictionary<string, object> dict);
}
class DictionaryConerter<T> : IDictionaryConverter where T : new()
{
public object Convert(IDictionary<string, object> dict)
{
return ConvertTyped(dict);
}
public T ConvertTyped(IDictionary<string, object> dict)
{
T t = new T();
PropertyInfo[] properties = t.GetType().GetProperties();
foreach (KeyValuePair<string, object> curr in dict)
{
if (String.IsNullOrEmpty(curr.Key)) continue;
if (curr.Value == null) continue;
Type valType = null;
Type newType = null;
PropertyInfo currProperty = null;
foreach (PropertyInfo p in properties)
{
if (String.IsNullOrEmpty(p.Name)) continue;
if (String.Compare(p.Name.ToLower(), curr.Key.ToLower()) == 0)
{
valType = t.GetType().GetProperty(p.Name).PropertyType;
newType = Nullable.GetUnderlyingType(valType) ?? valType;
currProperty = p;
break;
}
}
//you don't have to cast the object here, PropertyInfo.SetValue will accept it "as is":
object newVal = curr.Value;
IDictionary<string, object> curDict = curr.Value as IDictionary<string, object>;
IList curList = curr.Value as IList;
if (curDict != null && newType.GetConstructor(Type.EmptyTypes) != null)
{
newVal = ((IDictionaryConverter)Activator.CreateInstance(typeof(DictionaryConerter<>).MakeGenericType(newType))).Convert(curDict);
}
else if (
curList != null &&
curList.OfType<IDictionary<string,object>>().Any() &&
newType.IsGenericType &&
newType.GetGenericTypeDefinition() == typeof(List<>) &&
newType.GetGenericArguments()[0].GetConstructor(Type.EmptyTypes) != null)
{
newVal = ((ICollectionBuilder)Activator.CreateInstance(typeof(CollectionBuilder<>).MakeGenericType(newType.GetGenericArguments()[0]))).Build(curList);
}
t.GetType().GetProperty(currProperty.Name).SetValue(t, newVal);
}
return t;
}
}
class CollectionBuilder<T> : ICollectionBuilder where T : new()
{
public object Build(IList dictionaries)
{
DictionaryConerter<T> dictConverter = new DictionaryConerter<T>();
List<T> list = dictionaries
.OfType<IDictionary<string,object>>()
.Select(dict => dictConverter.ConvertTyped(dict))
.ToList();
return list;
}
}
以及用法:
BaseClass b = new DictionaryConerter<BaseClass>().ConvertTyped(outer);
當然,您可以將ICollectionBuilder
和IDictionaryConverter
的實例緩存在Dictionary<Type, ICollectionBuilder>
和Dictionary<Type, IDictionaryConverter>
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.