2013-02-02 25 views
2

我有我想要轉換爲正確的類型,然後處理它的JSON數據。我使用MONO和NewtonSoft的JSON庫。 I.E. JSON和對象必須匹配屬性1:1才能轉換爲正確的DTO。 DTO的總是具有獨特的屬性。如何將JSON動態轉換爲正確的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!"); 
    } 

} 

}

回答

1

我得到它的工作。我必須添加JsonSerializerSettings與MissingMemberHandling.Error,以便如果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); 
     } 

    } 

} 
1

我會假設你沒有自己從DTO類創建序列化的數據,因爲在那你可以簡單地在輸出中包含類型信息。有了這些信息,解串器將能夠自動重新創建正確的實例。

因爲這是最有可能不是你的情況,你需要解決以下幾個問題:

  1. 解析JSON,並與相應的屬性創建一個對象
  2. 確定哪些DTO實例給出的數據相匹配
  3. 創建DTO實例並使用步驟1中創建的對象填充它

我假設您已經或可以找到JSON解串器來處理fi第一步。

您可能有一個更簡單的方法來執行第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幫手 - 它會自動找到一個構造函數來調用並複製任何剩餘的匹配屬性。

我希望這可以指引您正確的方向。

相關問題