C#のでプロトコルバッファ:どのようにboxed値型を扱います
-
05-09-2019 - |
質問
以下の実施例において
public class RowData
{
public object[] Values;
}
public class FieldData
{
public object Value;
}
私がいるProtobuf-netのどちらかDOTNET-protobufsは、このようなクラスを扱うだろうかのように好奇心旺盛です。私がいるProtobufネットに精通していますので、私が実際に持っていることはあります:
[ProtoContract]
public class RowData
{
[ProtoMember(1)]
public object[] Values;
}
[ProtoContract]
public class FieldData
{
[ProtoMember(1)]
public object Value;
}
しかし、私は、「見つかりませ適したデフォルトオブジェクトのエンコードを」と言っていないエラーが発生します。これらのクラスを治療するための簡単な方法は、私は認識していないだということ、ありますか?
ユースケースにもっと詳しく説明します:
これは、リモートで使用されるデータクラスのダウンスケーリングされたバージョンです。だから、基本的に、それは次のようになります:
FieldData data = new FieldData();
data.Value = 8;
remoteObject.DoSomething(data);
注:私は簡単にするためにISerializable実装を省略しましたが、あなたが期待するとして、それは
。解決
(更新)
右;私のサンプルの主な問題は、上記の値ゲッターだった...それを考え出しました。彼らは例外を投げました。いくつかのライブラリグリッチが(今固定する)もあった。
しかし、最も簡単な方法はパススルーNullable<T>
特性
[ProtoMember(1)]
private int? ValueInt32
{
get { return Get<int>(); }
set { Value = value; }
}
など、と:
private T? Get<T>() where T : struct
{
return (Value != null && Value is T) ? (T?)Value : (T?)null;
}
このと*指定されたアプローチの両方が<のhref = "http://code.google.com/p/protobuf-net/source/browse/trunk/Examples/ValueWrapper.cs" のrel = "nofollowをnoreferrerされています「> をテストし、そして今も元気に動作します。
他のヒント
再いるProtobufネット、私は維持されます:
ここでの問題は、価値の種類(それは多くの場合、細かい処理します)ではない - それは単にそれをデコード/エンコードする方法ので、データが期待するものを知っている、としないことを意味オープンobject
の使用、です。
現時点では、私はそれを処理するための簡単な/きれいな方法を考えることはできません。これは、一般的な値型のシナリオ、リストの範囲、および契約(データ契約、プロト契約、またはいくつかのXML-スキーマ)に基づく階層の任意のレベルを処理しますが、それは、の手がかりを必要とします。のます。
あなたはユースケースを明確にすることができます場合は、おそらく、私はより多くのを助けることができるかもしれませんか?例えば、上記DataContractSerializer
またはXmlSerializer
のいずれかで非常に機能しないだろう...
DOTNET-protobufs再;私は実際にコメントすることはできませんが、私はそれもあまり寛容になりますかなり確信しています。 .protoファイルから生成されたクラスで使用することを意図しているので、object
は単にモデルに入ることはない(ジョン:私は間違っているなら、私を修正)
、あなたは親切に、ここでコメントを投稿することができ?だから私は簡単にそれを見つけることができます...また、(私のSOのプロフィールを参照)、直接私にメールをドロップします。
<時間>編集 - それは現時点では動作していないが、私は、なぜ明日(たぶん)を見つけ出すだろう - ここで私は念頭に置いていたハックの事です。理論的には、余分なメンバーは、すべてのプライベート可能性があります - 私はデバッグ中、それは簡単にしようとしています。これは余分なストレージを取らないことに注意してください。私が言うように、それは今日動作しませんが、それは必要があります - 私は見つけることができますなぜ...
[ProtoContract]
public class FieldData
{
public object Value {get;set;}
[ProtoMember(1)]
public int ValueInt32 {
get { return (int)Value; } set { Value = value; } }
public bool ValueInt32Specified {
get { return Value != null && Value is int; } set { } }
[ProtoMember(2)]
public float ValueSingle {
get { return (float)Value; } set { Value = value; } }
public bool ValueSingleSpecified {
get { return Value != null && Value is float; } set { } }
// etc for expected types
}
これは、私が考えていたもののようなものです。どう考えているか教えてください。当然のことながら、私は私がサポートする必要がある各値型のサブクラスを追加する必要があると思います。どう思いますか?より良い方法はあり、あなたがこの方法で任意の非効率性を見ていますか?
[ProtoContract, Serializable]
[ProtoInclude(1, typeof(Int32FieldData))]
public abstract class FieldDataBase : ISerializable
{
[ProtoIgnore]
public abstract object Value { get; set;}
protected FieldDataBase()
{ }
#region ISerializable Members
protected FieldDataBase(SerializationInfo info, StreamingContext context)
{
Serializer.Merge<FieldDataBase>(info, this);
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
Serializer.Serialize<FieldDataBase>(info, this);
}
#endregion
}
[ProtoContract, Serializable]
public class Int32FieldData : FieldDataBase
{
[ProtoMember(1)]
public int? Int32Value;
[ProtoIgnore]
public override object Value
{
get { return this.Int32Value.HasValue ? this.Int32Value : null; }
set { this.Int32Value = (int?)value; }
}
public Int32FieldData() { }
protected Int32FieldData(SerializationInfo info, StreamingContext context)
:base(info, context)
{ }
}
直接のカプセル化は、次のようにして、すべてのプロパティから追加なしオーバーヘッドで正常に動作するようです。
[ProtoContract, Serializable]
public class ObjectWrapper : ISerializable
{
public ObjectWrapper()
{ }
[ProtoIgnore]
public object Value
{
get
{
if (Int32Value.HasValue)
return Int32Value.Value;
else if (BinaryValue != null)
return BinaryValue;
else
return StringValue;
}
set
{
if (value is int)
this.Int32Value = (int)value;
else if (value is byte[])
this.BinaryValue = (byte[])value;
else if (value is string)
this.StringValue = (string)value;
}
}
[ProtoMember(1)]
private int? Int32Value;
[ProtoMember(2)]
private string StringValue;
[ProtoMember(3)]
private byte[] BinaryValue;
// etc
#region ISerializable Members
protected ObjectWrapper(SerializationInfo info, StreamingContext context)
{
Serializer.Merge<ObjectWrapper>(info, this);
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
Serializer.Serialize<ObjectWrapper>(info, this);
}
#endregion
}