2017-04-03 1 views
1

protobuf-netでクラスをシリアル化しようとすると、次のエラーが発生しました。 Hashtableにはさまざまな種類のオブジェクト配列が含まれているため、残念ながら辞書を使用することはできません。派生型のISiteがありますが、インタフェース自体が.NETの一部であれば、私が知る限りでは私ができることはあまりありません。protobuf-net使用時に「System.Collections.HashTable」または「System.ComponentModel.ISite」が定義されていないシリアライザ

私はRuntimeTypeModelについていくつかのことを調べましたが、あなたが作るカスタムクラスにしか適用されないことがわかります。どんな指導も大変ありがとう!ありがとう。

+0

RuntimeTypeModelは、任意のタイプ、あなたが作るだけでなく、クラスに適用されます。 – Evk

+0

'ISite'とは何ですか?それはインターフェースですか?私はそれがうまくいくとは思わない...インターフェースは実装であり、データではない。あなたはそれが何であるかについてより具体的になりますか? –

答えて

1

Hashtableがうまくいかない理由は、は、あなたがそれに入れようとしているものがわからないからです。。 protobuf-netは契約ベースのシリアライザです。 Hashtableは本質的にはobject-to-objectのマップです。 objectで、ではありません。実際、契約とは正反対です。対照的に、Dictionary<int, SomeType>SomeTypeを契約書として使用できる限り)のようにうまく動作します。

ISiteが機能しないのは、とおそらくのインターフェイスです。インタフェースは実装であり、データではありません。それが起こると、protobuf-net にインターフェイスメンバーのサポートをいくつか制限していますが、インターフェイスをDTO(データ契約)から遠ざけるほうがよいです。どのようなタイプのISite実装を作成する必要がありますか?それにはどんなデータが必要ですか?使用したSomeFunSite : ISiteは、どのようにインスタンス化され、物事に結び付けられるのですか?シリアライザが必要とする質問が多すぎます:シリアライザが望んでいることは、「Fooをシリアル化しています; Fooには2つの整数、文字列、Barがありますが、それについてはSuperBar : Barサブクラスもありますある場合"。それは十分な問題以上のものです。

良い契約:

[ProtoContract] 
public class MyData { 
    [ProtoMember(1)] 
    public Dictionary<int, SomeType> Items {get; } = new Dictionary<int, SomeType>(); 

    [ProtoMember(2)] 
    public SomethingElse Whatever { get;set;} 
} 

悪い契約:常にではない:いくつかのケースでは

[ProtoContract] 
public class MyData { 
    [ProtoMember(1)] 
    public Hashtable Items {get; } = new Hashtable(); 

    [ProtoMember(2)] 
    public ISometing Whatever { get;set;} 
} 

それはあなたがやろうとしたが、されているかを理解するためにRuntimeTypeModelを設定する可能性があります。それは文脈に依存するだろう。私が持っていない文脈。


編集:マイナー明確化:{get;}のみのプロパティは、今ではなく、現在のNuGetビルドで、ソースコードでサポートされている - 基本的には、まだそれを使用しないでください!


は、ここで保存する同様のデータをマーキングの実行可能な例を示します

using ProtoBuf; 
using System; 
using System.Collections.Generic; 

static class Program 
{ 
    static void Main() 
    { 
     var obj = new MyData 
     { 
      Site = new BasicSite { BaseHost = "http://somesite.org" }, 
      Items = 
      { 
       {"key 1", SomeType.Create(123) }, 
       {"key 2", SomeType.Create("abc") }, 
       {"key 3", SomeType.Create(new Whatever { Id = 456, Name = "def" }) }, 
      } 
     }; 

     var clone = Serializer.DeepClone(obj); 
     Console.WriteLine($"Site: {clone.Site}"); 
     foreach(var pair in clone.Items) 
     { 
      Console.WriteLine($"{pair.Key} = {pair.Value}"); 
     } 
    } 
} 


[ProtoContract] 
class MyData 
{ 
    private readonly Dictionary<string, SomeType> _items 
     = new Dictionary<string, SomeType>(); 
    [ProtoMember(1)] 
    public Dictionary<string, SomeType> Items => _items; 
    [ProtoMember(2)] 
    public ISite Site { get; set; } 
} 

[ProtoContract] 
[ProtoInclude(1, typeof(SomeType<int>))] 
[ProtoInclude(2, typeof(SomeType<string>))] 
[ProtoInclude(3, typeof(SomeType<Whatever>))] 
abstract class SomeType 
{ 
    public object Value { get { return UntypedValue; } set { UntypedValue = value; } } 
    protected abstract object UntypedValue { get; set; } 

    public static SomeType<T> Create<T>(T value) => new SomeType<T> { Value = value }; 
} 
[ProtoContract] 
class SomeType<T> : SomeType 
{ 
    [ProtoMember(1)] 
    public new T Value { get; set; } 
    protected override object UntypedValue { get => Value; set => Value = (T)value; } 
    public override string ToString() => Value?.ToString() ?? ""; 
} 
[ProtoContract] 
class Whatever 
{ 
    [ProtoMember(1)] 
    public int Id { get; set; } 
    [ProtoMember(2)] 
    public string Name { get; set; } 
    public override string ToString() => $"{Id}, {Name}"; 
} 
[ProtoContract] 
[ProtoInclude(1, typeof(BasicSite))] 
interface ISite 
{ 
    void SomeMethod(); 
} 
[ProtoContract] 
class BasicSite : ISite 
{ 
    void ISite.SomeMethod() { Console.WriteLine(BaseHost); } 
    [ProtoMember(1)] 
    public string BaseHost { get; set; } 
    public override string ToString() => BaseHost; 
} 
+0

私が言ったようなHashTableは、基本的にはです。 ISite変数は、インターフェイスから派生した2つの型の1つになるため、おそらく私はそれらの2つの派生型でテストできます。 –

+0

2つの 'ISite'実装がかなりシンプルであれば@Varun、[ProtoInclude]はそれをすべて動作させる可能性があります。例がないと伝えにくい。しかし、 "(互いに関連しない複数のタイプがあるかもしれない)"は、いい契約ではありません**。しかし、確かな契約でそれを表現する方法はあります。たとえば、既知の複数のコンテナサブクラスを宣言する共通の基底クラスです。これは 'SomeBaseClass'と' SomeDerivedClass '(そして' ProtoInclude 'を使っていろいろな 'T'を宣言します)によって最も便利に行うことができます。繰り返しますが、それに対処する方法を示すための例を見る必要があります。 –

+0

@VarunSablok答えに実行可能な例を追加しました –

関連する問題