2

正しい型に変換して処理したいJSONデータがあります。MONO と NewtonSoft の JSON ライブラリを使用しています。IE JSON とオブジェクトは、適切な DTO に変換するために、プロパティが 1:1 で一致する必要があります。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!");
    }

}

}

4

2 に答える 2

1

DTO クラスからシリアル化されたデータを自分で作成していないと仮定します。その場合、単純に出力に型情報を含めることができるからです。この情報が利用可能になると、デシリアライザーは正しいインスタンスを自動的に再作成できます。

これはおそらくあなたのケースではないため、次の問題を解決する必要があります。

  1. JSON を解析し、対応するプロパティを持つオブジェクトを作成します
  2. 指定されたデータに一致する DTO インスタンスを特定する
  3. DTO インスタンスを作成し、ステップ 1 で作成したオブジェクトを使用してデータを取り込みます

最初のステップを処理するための 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 ヘルパーです。コンストラクターを自動的に見つけて、残りの一致するプロパティを呼び出してコピーします。

これがあなたを正しい方向に向けてくれることを願っています。

于 2013-02-02T20:57:08.207 に答える
1

私はそれを働かせました。JSON がオブジェクトに収まらない場合に例外がスローされるように、JsonSerializerSettings に MissingMemberHandling.Error を追加する必要がありました。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);
        }

    }

}
于 2013-02-05T20:25:38.083 に答える