3

PropertyInfoのシリアル化はサポートされることになっていますか?そうでない場合、最善の回避策は何ですか?タイプ(サポートされている)をシリアル化してから、その属性でプロパティをルックアップすることが可能であることを私は知っています-ルックアップはおそらく費用がかかると想像してください。

ps PropertyInfoは、DataLoadOptions.LoadWithhttp://msdn.microsoft.com/en-us/library/bb548760.aspxと同様の機能の実装に使用されます

using System.IO;
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ProtoBuf;

[ProtoContract]
public class A
{
    [ProtoMember(1)]
    public PropertyInfo Property { get; set; }
}

[TestClass]
public class UnitTest
{
    [TestMethod]
    public void TestMethod1()
    {
        var value = new A { Property = typeof(string).GetProperty("Length") };
        using (var stream = new MemoryStream())
        {
            // Raises InvalidOperationException
            // "No serializer defined for type: System.Reflection.PropertyInfo"
            Serializer.Serialize(stream, value);
        }
    }
}

InvalidOperationExceptionが発生したときにスタックを呼び出します。

protobuf-net.dll!ProtoBuf.Meta.ValueMember.BuildSerializer() Line 316   C#
protobuf-net.dll!ProtoBuf.Meta.ValueMember.Serializer.get() Line 188 + 0x24 bytes   C#
protobuf-net.dll!ProtoBuf.Meta.MetaType.BuildSerializer() Line 421 + 0x1f bytes C#
protobuf-net.dll!ProtoBuf.Meta.MetaType.Serializer.get() Line 344 + 0xe bytes   C#
protobuf-net.dll!ProtoBuf.Meta.RuntimeTypeModel.Serialize(int key, object value, ProtoBuf.ProtoWriter dest) Line 592 + 0x44 bytes   C#
protobuf-net.dll!ProtoBuf.Meta.TypeModel.SerializeCore(ProtoBuf.ProtoWriter writer, object value) Line 178 + 0x14 bytes C#
protobuf-net.dll!ProtoBuf.Meta.TypeModel.Serialize(System.IO.Stream dest, object value, ProtoBuf.SerializationContext context) Line 209 + 0xe bytes C#
protobuf-net.dll!ProtoBuf.Meta.TypeModel.Serialize(System.IO.Stream dest, object value) Line 193 + 0x10 bytes   C#
protobuf-net.dll!ProtoBuf.Serializer.Serialize<TestProtoBufNet.A>(System.IO.Stream destination, TestProtoBufNet.A instance) Line 88 + 0x18 bytes    C#
TestProtoBufNet.dll!TestProtoBufNet.UnitTest.TestMethod1() Line 24 + 0x10 bytes C#
4

2 に答える 2

3

@ikhがすでに言ったことを追加するために、それはサポートされているタイプではありません。標準のBCLタイプを参照するときは、リフレクションタイプではなく、一般的なデータタイプについて話します。protobufとprotobuf-netの全体的なポイントはデータ中心である必要がありますが、PropertyInfoなどはデータではなく実装です。実際、WinRTは、持つべき情報の量について非常に異なる考え方PropertyInfoを持っています。

でも!シリアル化することにした場合は、IIRCType がサポートされていることに注意してください。したがって、サロゲートを介してこれを行うことができます(完全にテストされていません。ここではiPadを使用しています!)。

[ProtoContract]
public class PropertyInfoSurrogate {
    [ProtoMember(1)]
    public Type Type { get; set; }
    [ProtoMember(2)]
    public string Name { get; set; }

    public static operator implicit PropertyInfoSurrogate(PropertyInfo value) {
        if(value == null) return null;
        return new PropertyInfoSurrogate {
             Type = value.DeclaringType, Name = value.Name
        };
    }
    public static operator implicit PropertyInfo(PropertyInfoSurrogate value) {
        if(value == null) return null;
        return value.Type.GetProperty(value.Name);
    }
}

次に、モデルに:

model.Add(typeof(PropertyInfo), false)
    .SetSurrogate(typeof(PropertyInfoSurrogate));

強調:完全にテストされていませんが、そのようものは機能するはずです。どうやって乗るのか教えてください。

于 2012-07-27T17:10:27.313 に答える
1

残念ながら、PropertyInfoprotobuf-netではシリアル化できないようです。その中のデータをシリアル化するには、おそらくProtoContract、の関連ビットを格納する別のクラスを作成しPropertyInfo、それを使用する必要があります。

具体的には、protobuf-netが複合型(ここここ)のシ​​リアライザーを見つける方法のソースコードを読むと、protobufは-like属性を持つクラス[DataContract]、特に次のいずれかでのみ機能するように見えます。

他の人とは連携しません。

簡単な実験でこれを確認します。次のコードは例外なく実行されますが、[DataContract][DataMember]がコメントアウトされている場合は、同じ例外が発生します。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;

using ProtoBuf;

namespace ProtobufNetTest2 {
    [DataContract(Name = "Pet", Namespace = "http://www.example.com")]
    public class Pet  {
        [DataMember(Name = "Name")]
        public string Name { get; set; }
    }

    [ProtoContract]
    public class DogMessage {
        [ProtoMember(1)]
        public Pet Dog { get; set; }
    }

    class Program {
        static void Main(string[] args) {
            var dog = new Pet() {
                Name = "The Dog",
            };

            var dogMessage = new DogMessage() {
                Dog = dog,
            };

            using (var stream = new MemoryStream()) {
                Serializer.Serialize(stream, dogMessage);
            }
        }
    }
}
于 2012-07-27T15:56:08.950 に答える