2

逆シリアル化しようとしているオブジェクトの型を指定しているにもかかわらず、json.net で「型はインターフェイスです。インスタンス化できません」という逆シリアル化エラーが発生します。

private static JsonSerializerSettings settings = new JsonSerializerSettings { 
    TypeNameHandling = TypeNameHandling.Auto };

/// <summary>
/// Returns an object created from the jObject and placed in a stub object
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="jObj"></param>
/// <returns></returns>
public static T FromJObject<T>(JToken jObj)
{
    if (jObj == null)
    {
        jObj = new JObject();
    }
    if (jObj is JValue)
    {
        return (T)((JValue)jObj).Value;
    }
    else
    {
        return (T)JsonConvert.DeserializeObject<T>(jObj.ToString(), settings);
    }
 }

これはjOBJです

{
  "Id": 2,
  "Name": "Name",
  "JsonMapEnum": 0,
  "Validations": [
    {
      "Id": 1,
      "$type": "JsonMap.Default.JValidation, JsonMap"
    }
  ],
  "JSType": 3,
  "SubJsonMapEnum": -1,
  "$type": "JsonMap.Default.JAttribute, JsonMap"
}

これがエラーです

Could not create an instance of type JsonMap.Interfaces.IValidation. Type is an interface or abstract class and cannot be instantated. Path 'Validations[0].Id'

Id を Validation オブジェクトに変換しようとしているようです。なんで?

これらは私のタイプによって実装されたインターフェースです

public interface IJsonMap
{
    long Id { get; set; }
    String Name { get; set; }
    LazyEnum JsonMapEnum { get; set; }
}

public interface IAttribute : IJsonMap
{
    IEnumerable<IValidation> Validations { get; set; }
    LazyEnum JSType { get; set; }
    LazyEnum SubJsonMapEnum { get; set; }
}

public interface IValidation : IJsonMap
{
    IEnumerable<IArgument> Arguments { get; set; }
}

これが呼び出しです

FromJObject<JAttribute>(CreationJObj)

JAttribute は IAttribute を実装します

4

2 に答える 2

2

どうやら、「$type」は文字列リテラルの最初のプロパティである必要があり、型が型名ハンドラーによってキャッチされるようになっています。これは、デシリアライザーが $type の存在をチェックしておらず、単に json 文字列リーダーを使用しており、タイプが設定されていない最初のプロパティを見つけると失敗したためだと思います。

$type が常に最初になるように作成したメソッドは次のとおりです

    private static JToken ReorderJToken(this JToken jTok)
    {
        if (jTok is JArray)
        {
            var jArr = new JArray();
            foreach (var token in jTok as JArray)
            {
                jArr.Add(token.ReorderJToken());
            }
            return jArr;
        }
        else if( jTok is JObject)
        {
            var jObj = new JObject();
            foreach(var prop in (jTok as JObject).Properties().OrderBy(x=> x.Name))
            {
                prop.Value = prop.Value.ReorderJToken();
                jObj.Add(prop);
            }
            return jObj;
        }
        return jTok;
    }
于 2013-05-07T18:25:58.967 に答える
0

明らかに、与えている引数に基づいて適切な型を推測することはできません。それがどのように呼ばれているかについてのコンテキストがなければ、あなたが持っているものを機能させることはできません。ただし、interfaces 型にキャストされたオブジェクトで呼び出すと、機能しません。あなたが持っている定義では、常にクラスの型でFromObject呼び出されなければなりません。最初にすべきことは、メソッド where is equal toTを決して呼び出そうとしないことです。これは失敗することが保証されているためです。それでも解決しない場合は、別のバージョンの deserialize メソッドを呼び出してみます。Ttypeof(IOneOfMyInterfaces)

IMyInterface obj = (IMyInterface)serializer.Deserialize(validatingReader, t);

これは、validatingReader が でありJsonReadertType実装するクラス オブジェクトの である場合に機能しますIMyInterface。私は現在、jsonの正確性を検証するためのjsonスキーマを使用した一般的な逆シリアル化に使用しています。

于 2013-05-07T16:31:52.043 に答える