2016-09-05 6 views
1

私は、Json.netを使用して以下のクラスをシリアル化およびデシリアライズしようとしています。Json.netコレクションは固定サイズでした

public class OperationBase 
{ 
} 

public class OperationCreate : OperationBase 
{ 
    public string Entity 
    { 
     get; 
     private set; 
    } 

    public IReadOnlyCollection<string> Attributes 
    { 
     get; 
     private set; 
    } 

    public OperationCreate(string entity, params string[] attributes) 
    { 
     Contract.Requires(entity != null); 
     Contract.Requires(attributes != null); 

     Entity = entity; 
     Attributes = attributes; 
    } 
} 

public class OperationUpdate : OperationCreate 
{ 
    public OperationUpdate(string entity, params string[] attributes) 
     : base(entity, attributes) 
    { 
    } 
} 

public class OperationAssign : OperationUpdate 
{ 
    public OperationAssign(string entity) 
     : base(entity, "ownerid") 
    { 
    } 
} 

次のコードを使用してください。私が正しくOperationCreateOperationUpdateをシリアライズとデシリアライズすることができます

public void SerialiseTest<T>(T t) 
{ 
    string serialised = JsonConvert.SerializeObject(t, Formatting.Indented, new JsonSerializerSettings() 
    { 
     TypeNameHandling = TypeNameHandling.All, 
    }); 

    ITraceWriter traceWriter = new MemoryTraceWriter(); 

    T deserialised = JsonConvert.DeserializeObject<T>(serialised, new JsonSerializerSettings() 
    { 
     TraceWriter = traceWriter, 
     TypeNameHandling = TypeNameHandling.All, 
    }); 

    deserialised.ShouldBeEquivalentTo(t); 
} 

[TestMethod] 
public void Test() 
{ 
    OperationCreate create = new OperationCreate("Create", new string[] { "ownerid" }); 

    OperationUpdate update = new OperationUpdate("Update", new string[] { "ownerid" }); 

    OperationAssign assign = new OperationAssign("Test"); 

    SerialiseTest(create); 
    SerialiseTest(update); 
    SerialiseTest(assign); //Exception! 
} 

は、しかし、私はOperationAssignにこのエラーが表示されます。

System.NotSupportedException: Collection was of a fixed size.

私はなぜ理解していないか、私はこれをさらにデバッグすることができますか。 OperationAssignは基本的には、基本クラス(OperationCreateOperationUpdate)にパラメータを渡すだけです。このクラスは、直列化と逆直列化が正常に行われます。

この問題を解決するにはどうすればよいですか?

直列OperationAssign

{ 
    "$type": "Woodswork.Crm.Documenter.Data.Operations.OperationAssign, Woodswork.Crm.Documenter", 
    "Entity": "Test", 
    "Attributes": { 
    "$type": "System.String[], mscorlib", 
    "$values": [ 
     "ownerid" 
    ] 
    } 
} 

TraceWriter

2016-09-05T22:14:44.813 Verbose Resolved type 'Woodswork.Crm.Documenter.Data.Operations.OperationAssign, Woodswork.Crm.Documenter' to Woodswork.Crm.Documenter.Data.Operations.OperationAssign. Path '$type', line 2, position 95. 
2016-09-05T22:14:44.813 Info Deserializing Woodswork.Crm.Documenter.Data.Operations.OperationAssign using creator with parameters: Entity. Path 'Entity', line 3, position 11. 
2016-09-05T22:14:44.813 Verbose Resolved type 'System.String[], mscorlib' to System.String[]. Path 'Attributes.$type', line 5, position 40. 
2016-09-05T22:14:44.813 Info Started deserializing System.String[]. Path 'Attributes.$values', line 6, position 16. 
2016-09-05T22:14:44.813 Info Finished deserializing System.String[]. Path 'Attributes.$values', line 8, position 5. 
2016-09-05T22:14:44.815 Info Started deserializing Woodswork.Crm.Documenter.Data.Operations.OperationAssign. Path '', line 10, position 1. 
2016-09-05T22:14:44.824 Error Error deserializing Woodswork.Crm.Documenter.Data.Operations.OperationAssign. Collection was of a fixed size. Path '', line 10, position 1. 

代替OperationAssignコンストラクタこれももたらす

同じエラー。

public OperationAssign(string entity) 
    : base(entity, new string[] { "ownerid" }) 
{ 
} 

答えて

2

問題は、あなたがOperationAssignAttributesコレクションをデシリアライズしようとし、その後シリアライズされていることである - しかし、コレクションは読み取り専用とプロパティが公に設定可能ではありませんようJson.NETは、それをデシリアライズする方法がありません。

Json.NETは、それがパラメータとプロパティと同じ名前(モジュロケース)とパラメータ、すなわちattributesである単一のコンストラクタを有しているので正常基底クラスOperationUpdateをデシリアライズすることが可能です。そのような場合、Json.NETはコンストラクタを呼び出し、JSONファイルから直列化された「属性」の値を渡します。残念ながら、派生クラスはこのコンストラクタを省略しているため、逆シリアル化は失敗します。

あなたはこの問題を回避するには、いくつかのアプローチがあります:

  1. 適切なパラメータを持つコンストラクタを追加し、[JsonConstructor]としてマークを。これは、民間のようになります。

    public class OperationAssign : OperationUpdate 
    { 
        [JsonConstructor] 
        OperationAssign(string entity, params string[] attributes) : this(entity) 
        { 
        } 
    
        public OperationAssign(string entity) 
         : base(entity, "ownerid") 
        { 
        } 
    } 
    

    したい場合は、デシリアライズ属性のを無視することができます。パラメータは単に存在する必要があります。conditional property serializationを使用して、派生クラスの属性の

  2. 抑制シリアライゼーション:

    public class OperationCreate : OperationBase 
    { 
        public string Entity 
        { 
         get; 
         private set; 
        } 
    
        public IReadOnlyCollection<string> Attributes 
        { 
         get; 
         private set; 
        } 
    
        public virtual bool ShouldSerializeAttributes() { return true; } 
    
        public OperationCreate(string entity, params string[] attributes) 
        { 
         Contract.Requires(entity != null); 
         Contract.Requires(attributes != null); 
    
         Entity = entity; 
         Attributes = attributes; 
        } 
    } 
    
    public class OperationAssign : OperationUpdate 
    { 
        public OperationAssign(string entity) 
         : base(entity, "ownerid") 
        { 
        } 
    
        public override bool ShouldSerializeAttributes() { return false; } 
    } 
    

    基底クラスが仮想ShouldSerializeAttributes()方法を介してこれをサポートしなければなりません。

  3. 基本クラスに[JsonProperty]のプロパティをマークします。これは、民間のセッターが呼ばれるように強制します:

    public class OperationCreate : OperationBase 
    { 
        public string Entity 
        { 
         get; 
         private set; 
        } 
    
        [JsonProperty] 
        public IReadOnlyCollection<string> Attributes 
        { 
         get; 
         private set; 
        } 
    
        public OperationCreate(string entity, params string[] attributes) 
        { 
         Contract.Requires(entity != null); 
         Contract.Requires(attributes != null); 
    
         Entity = entity; 
         Attributes = attributes; 
        } 
    } 
    

サンプルfiddleをオプションを示します。

0

私はJson.netからの配列入力を受け取るために追加のコンストラクタを用意しなければなりませんでした。

[JsonConstructor] 
public OperationAssign(string entity, params string[] attributes) 
    : base(entity, attributes) 
{ 
} 
関連する問題