我有JSON数据,我想将其转换为正确的类型,然后处理它。我正在使用MONO和NewtonSoft的JSON库。 I.E. JSON和对象必须匹配属性1:1才能转换为右DTO。 DTO始终具有独特的属性。
Activator.CreateInstance()和Convert.ChangeType()似乎都没有编译。
的DTO:
class JSONDTO
{
}
class JSONCommandDTO : JSONDTO
{
public string cmd;
}
class JSONProfileDTO : JSONDTO
{
public string nick;
public string name;
public string email;
}
class JSONMessageDTO : JSONDTO
{
public string msg;
}
服务器:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Newtonsoft.Json;
class Server
{
protected static List<JSONDTO> DTOList;
static void Main()
{
DTOList = new List<JSONDTO>();
DTOList.Add(new JSONProfileDTO());
DTOList.Add(new JSONCommandDTO());
DTOList.Add(new JSONMessageDTO());
// ...
}
protected static void OnMessage (string message)
{
dynamic rawObject;
try
{
// Or try to convert to right DTO here somehow?
rawObject = JsonConvert.DeserializeObject<dynamic>(message);
} catch (JsonReaderException ex) {
// Invalid JSON
return;
}
int dtoCount = DTOList.ToArray().Length;
int errCount = 0;
JSONDTO DTOObject;
foreach (var dto in DTOList.ToList()) {
try {
// Doesn't compile:
// DTOObject = Activator.CreateInstance(dto.GetType(), rawObject);
// DTOObject = Convert.ChangeType(rawObject, dto.GetType());
break; // Match found!
} catch (Exception ex) {
// Didn't match
errCount++;
}
}
if (errCount == dtoCount) {
// Right DTO was not found
return;
}
if (DTOObject is JSONProfileDTO) {
AssignProfile((JSONProfileDTO) DTOObject);
}
else if (DTOObject is JSONCommandDTO)
{
RunCommand((JSONCommandDTO) DTOObject);
}
// etc ..
}
protected static void RunCommand (JSONCommandDTO command)
{
string cmd = command.cmd;
Console.WriteLine("command == " + cmd);
}
protected static void AssignProfile(JSONProfileDTO profile)
{
Console.WriteLine("got profile!");
}
}
}
答案 0 :(得分:1)
我将假设您没有自己从DTO类创建序列化数据,因为在这种情况下,您可以简单地在输出中包含类型信息。有了这些信息,解串器将能够自动重新创建正确的实例。
由于这很可能不是您的情况,您需要解决以下问题:
我假设您已经或者可以找到JSON反序列化器来处理第一步。
您可能有更简单的方法来执行第2步,但简单的方法只是比较JSON数据中可用的属性名称,并找到完全匹配的DTO。这可能看起来像这样(使用Fasterflect来协助反射位):
var types = [ typeof(JSONCommandDTO), typeof(JSONProfileDTO), typeof(JSONMessageDTO) ];
var json = deserializer.GetInstance( ... );
var jsonPropertyNames = json.GetType().Properties( Flags.InstancePublic )
.OrderBy( p => p.Name );
var match = types.FirstOrDefault( t => t.Properties( Flags.InstancePublic )
.OrderBy( p => p.Name )
.SequenceEqual( jsonPropertyNames ) );
if( match != null ) // got match, proceed to step 3
步骤3的代码可能如下所示:
// match is the DTO type to create
var dto = match.TryCreateInstance( json );
TryCreateInstance是另一个Fasterflect助手 - 它会自动找到一个构造函数来调用和复制任何剩余的匹配属性。
我希望这能指出你正确的方向。
答案 1 :(得分:1)
我得到了它的工作。我不得不使用MissingMemberHandling.Error添加JsonSerializerSettings,以便在JSON不适合对象时抛出异常。我也缺少Microsoft.CSharp参考。
class Server
{
protected static List<Type> DTOList = new List<Type>();
static void Main()
{
DTOList.Add(typeof(JSONProfileDTO));
DTOList.Add(typeof(JSONCommandDTO));
DTOList.Add(typeof(JSONMessageDTO));
}
protected static void OnMessage (string rawString)
{
dynamic jsonObject = null;
int DTOCount = DTOList.Count;
int errors = 0;
var settings = new JsonSerializerSettings ();
// This was important
// Now exception is thrown when creating invalid instance in the loop
settings.MissingMemberHandling = MissingMemberHandling.Error;
foreach (Type DTOType in DTOList) {
try {
jsonObject = JsonConvert.DeserializeObject (rawString, DTOType, settings);
break;
} catch (Exception ex) {
errors++;
}
}
if (null == jsonObject) {
return;
}
if (errors == DTOCount) {
return;
}
if (jsonObject is JSONProfileDTO) {
AssignProfile((JSONProfileDTO) jsonObject);
}
else if (jsonObject is JSONCommandDTO)
{
RunCommand((JSONCommandDTO) jsonObject);
}
}
}