gpt4 book ai didi

c# - 在没有 typeNameHandling 的情况下将 Json 对象反序列化为多态 C# 对象

转载 作者:行者123 更新时间:2023-11-30 12:30:18 26 4
gpt4 key购买 nike

我的问题是我想将一个 json 对象反序列化为一个 C# 对象,但诀窍在于 C# 对象包含 List< abstract class > 而这个抽象类是另外 10 个类的父类(super class)。

public sealed class SearchAPIResult
{
public string Status;

public SearchAPIQuery Query;

public SearchResults Result;

public SearchAPIResult()
{

}

public SearchAPIResult(string status)
{
Status = status;
}
}

SearchAPIResult是:

public sealed class SearchResults
{
public string TextAnswer;

public List<APIResultWidget> Items;

public SearchResults()
{
Items = new List<APIResultWidget>();
}
}

这里的对象 APIResultWidget 是一个抽象类,大约有 10 个类继承自它。

问题是 JSON 对象没有自动的东西(比如 JSON.NET 中的 typeNameHandling)来引导反序列化器将 10 个派生类中的哪个对象转换为。相反,对象由两个字段标记:类型和子类型...如下所示

{
"Status": "OK",
"Query": {
"Query": "this is a query",
"QueryLanguage": "EN"
},
"Result": {
"TextAnswer": "This is your text answer",
"Items": [{
"Type": "list",
"SubType": null,
"Title": null,
"Items": []
}, {
"Type": "text",
"Content": "this is some content"
}
]
}
}

在前面的json对象中,Result列表包含两个对象,一个:

{
"Type": "list",
"SubType": null,
"Title": null,
"Items": []
}

它映射到一个类型为 listWidget 的类(它继承自抽象 APIResultWidget 和两个:

{
"Type": "text",
"Content": "this is some content"
}

它映射到类textWidget,它也继承自相同的抽象类

当我使用Json.NET方式时

SearchAPIResult converted = (SearchAPIResult)JsonConvert.DeserializeObject(json, typeof(SearchAPIResult), new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto });

它抛出以下异常:

Could not create an instance of type Kngine.API.APIResultWidget. Type is an interface or abstract class and cannot be instantiated. Path 'Result.Items[0].Type', line 1, position 136.

我猜有一种自定义方式指出该类型由字段 Type 和 SubType 定义,并为 Converter 提供自定义类型注释器,对吗?

最佳答案

实际上我实现的解决方案是非常基本的解决方案,我从System.Web.Extentions扩展了JavaScriptConverter类,我实现了deseriealize方法,它自动接收原始对象中的每个小json对象作为Dictionary,我可以根据对象本身填写字段,这是一种手动方式,但这是我能想出并起作用的唯一解决方案,自定义类实现如下所示:

class myCustomResolver  : JavaScriptConverter

{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
if (type == typeof(APIResultWidget))
{
switch ((string)dictionary["Type"])
{
case "weather":
{
WeatherWidget x = new WeatherWidget();
x.Location = (string)dictionary["Location"];
x.Current = (CurrentWeather)dictionary["Current"];
//x.Forcast = (List<WeatherForcastItem>)dictionary["Forcast"];

System.Collections.ArrayList itemss = ((System.Collections.ArrayList)dictionary["Forcast"]);
foreach (var item in itemss)
{
x.Forcast.Add(serializer.ConvertToType<WeatherForcastItem>(item));
}

return x;
};
case "text":
{
TextWidget x = new TextWidget();
x.Content = (string)dictionary["Content"];
return x;
};
case "keyValueText":
{
KeyValueTextWidget x = new KeyValueTextWidget();
x.Key = (string)dictionary["Key"];
x.Key = (string)dictionary["Value"];
x.Key = (string)dictionary["ValueURL"];
return x;
};
case "keyValuesText":
{
KeyValuesTextWidget x = new KeyValuesTextWidget();
x.Key = (string)dictionary["Key"];
//x.Values = (List<ValueItem>)dictionary["ValueItem"];

System.Collections.ArrayList itemss = ((System.Collections.ArrayList)dictionary["ValueItem"]);
foreach (var item in itemss)
{
x.Values.Add(serializer.ConvertToType<ValueItem>(item));
}


return x;


};
case "url":
{
URLWidget x = new URLWidget();
x.ThumbnailImageURL = (string)dictionary["ThumbnailImageURL"];
x.Title = (string)dictionary["Title"];
x.URL = (string)dictionary["URL"];
x.HTMLContent = (string)dictionary["HTMLContent"];
return x;

};
case "map":
{
MapWidget x = new MapWidget();
System.Collections.ArrayList itemss = ((System.Collections.ArrayList)dictionary["Pins"]);
foreach (var item in itemss)
{
x.Pins.Add(serializer.ConvertToType<MapPoint>(item));
}

//x.Pins = (List<MapPoint>)dictionary["Pins"];
return x;

};
case "image":
{
ImageWidget x = new ImageWidget();
x.Title = (string)dictionary["Title"];
x.ImageURL = (string)dictionary["ImageURL"];
x.ThumbnailURL = (string)dictionary["ThumbnailURL"];
x.PageURL = (string)dictionary["PageURL"];
return x;
};
case "html":
{
HTMLWidget x = new HTMLWidget();
x.Title = (string)dictionary["Title"];
x.HTML = (string)dictionary["HTML"];
return x;


};
case "entity":
{
EntityWidget x = new EntityWidget();
x.SubType = (string)dictionary["SubType"];
x.Title = (string)dictionary["Title"];
x.Abstract = (string)dictionary["Abstract"];
x.ImageURL = (string)dictionary["ImageURL"];
x.Url = (string)dictionary["Url"];
return x;

};
case "chart":
{
ChartWidget x = new ChartWidget();
x.Title = (string)dictionary["Title"];
//x.Categories = (List<string>)dictionary["Categories"];
System.Collections.ArrayList itemss = ((System.Collections.ArrayList)dictionary["Categories"]);
foreach (var item in itemss)
{
x.Categories.Add(serializer.ConvertToType<string>(item));
}



System.Collections.ArrayList itemss2 = ((System.Collections.ArrayList)dictionary["Data"]);
foreach (var item in itemss2)
{
x.Data.Add(serializer.ConvertToType<ChartsData>(item));
}

//x.Data = (List<ChartsData>)dictionary["Data"];
return x;
};
case "businessEntity":
{
BusinessEntityWidget x = new BusinessEntityWidget();
x.SubType = (string)dictionary["SubType"];
x.Title = (string)dictionary["Title"];
x.Abstract = (string)dictionary["Abstract"];
x.ImageURL = (string)dictionary["ImageURL"];
x.URL = (string)dictionary["URL"];
//x.Attributes = (List<KeyValueTextWidget>)dictionary["Attributes"];
System.Collections.ArrayList itemss = ((System.Collections.ArrayList)dictionary["Attributes"]);
foreach (var item in itemss)
{
x.Attributes.Add(serializer.ConvertToType<KeyValueTextWidget>(item));
}

x.Address = (string)dictionary["Address"];
x.Phone = (string)dictionary["Phone"];
x.Lat = (double)dictionary["Lat"];
x.Lng = (double)dictionary["Lng"];


System.Collections.ArrayList itemss2 = ((System.Collections.ArrayList)dictionary["OtherURLs"]);
foreach (var item in itemss2)
{
x.OtherURLs.Add(serializer.ConvertToType<URLWidget>(item));
}
//x.OtherURLs = (List<URLWidget>)dictionary["OtherURLs"];

return x;



};

case "list":
{
switch ((string)dictionary["SubType"])
{
case null:
{
ListWidget x = new ListWidget();
x.Title = (string)dictionary["Title"];
System.Collections.ArrayList itemss = ((System.Collections.ArrayList)dictionary["Items"]);
foreach (var item in itemss)
{
x.Items.Add(serializer.ConvertToType<APIResultWidget>(item));
}
return x;

};
case "videos":
{
ListOfVideosWidget x = new ListOfVideosWidget();

System.Collections.ArrayList itemss = ((System.Collections.ArrayList)dictionary["Items"]);
foreach (var item in itemss)
{
x.Items.Add(serializer.ConvertToType<URLWidget>(item));
}
return x;
};
case "images":
{
ListOfImagesWidget x = new ListOfImagesWidget();


System.Collections.ArrayList itemss = ((System.Collections.ArrayList)dictionary["Items"]);
foreach (var item in itemss)
{
x.Items.Add(serializer.ConvertToType<ImageWidget>(item));
}
return x;
};
case "webResults":
{

ListOfWebsitesWidget x = new ListOfWebsitesWidget();

System.Collections.ArrayList itemss = ((System.Collections.ArrayList)dictionary["Items"]);
foreach (var item in itemss)
{
x.Items.Add(serializer.ConvertToType<URLWidget>(item));
}
return x;
};
case "businesses":
{
ListOfBusinessesWidget x = new ListOfBusinessesWidget();
x.Title = (string)dictionary["Title"];
System.Collections.ArrayList itemss = ((System.Collections.ArrayList)dictionary["Items"]);
foreach (var item in itemss)
{
x.Items.Add(serializer.ConvertToType<BusinessEntityWidget>(item));
}
return x;
};



}
}; break;


}
}

else //in case of objects not inheriting from the abstract class, in this case we identify each one by something else, not "type"
{
if (dictionary.ContainsKey("Day")) //WeatherForcastItem
{
WeatherForcastItem x = new WeatherForcastItem();
x.Day = (string)dictionary["Day"];
x.Hi = (string)dictionary["Hi"];
x.Lo = (string)dictionary["Lo"];
x.Status = (string)dictionary["Status"];
x.IconURL = (string)dictionary["IconURL"];
return x;

}
else if (dictionary.ContainsKey("Temprature")) // CurrentWeather
{
CurrentWeather x = new CurrentWeather();
x.Temprature = (string)dictionary["Temprature"];
x.Status = (string)dictionary["Status"];
x.WindSpeed = (string)dictionary["WindSpeed"];
x.WindDirection = (string)dictionary["WindDirection"];
x.Humidity = (string)dictionary["Humidity"];
x.IconURL = (string)dictionary["IconURL"];
x.IsNight = (string)dictionary["IsNight"];
return x;

}
else if (dictionary.ContainsKey("Lat")) //MapPoint
{
MapPoint x = new MapPoint();
x.Title = (string)dictionary["Title"];
x.Lat = (double)dictionary["Lat"];
x.Lng = (double)dictionary["Lng"];
return x;
}
else if (dictionary.ContainsKey("Value")) //ValueItem
{
ValueItem x = new ValueItem();
x.Value = (string)dictionary["Value"];
x.ValueURL = (string)dictionary["ValueURL"];
return x;
}
else if (dictionary.ContainsKey("name")) //ChartsData
{
ChartsData x = new ChartsData();
x.name = (string)dictionary["name"];
System.Collections.ArrayList itemss = ((System.Collections.ArrayList)dictionary["name"]);
foreach (var item in itemss)
{
x.values.Add(serializer.ConvertToType<string>(item));
}
return x;
}
}
return null;
}

public override IDictionary<string, object> Serialize(
object obj,
JavaScriptSerializer serializer)
{ return null; }

private static readonly Type[] _supportedTypes = new[]
{
typeof( APIResultWidget )
};

public override IEnumerable<Type> SupportedTypes
{
get { return _supportedTypes; }
}

}

这应该将每个 json 对象映射到它正确的类,然后解串器的使用相当简单:

var serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new[] { new myCustomResolver() });
var dataObj = serializer.Deserialize<SearchAPIResult>(response);

这解决了我在使用抽象类时遇到的反序列化问题,因为它首先完全解决了类之间如何相互关联的问题。我不知道这是否是最正确的解决方案,但至少它解决了我的问题

关于c# - 在没有 typeNameHandling 的情况下将 Json 对象反序列化为多态 C# 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16519893/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com