Protobuf net 序列化复杂属性而不使用属性

Protobuf net 序列化复杂属性而不使用属性,protobuf-net,Protobuf Net,我有一个项目,其中无法对要序列化的类型使用序列化属性。一般来说,我通过这样做使其工作: private byte[] Serialize(object value) { var type = value.GetType(); var typeModel = RuntimeTypeModel.Default.Add(type, false); foreach (var prop in type.GetProperties(BindingFlags.Public | Bin

我有一个项目,其中无法对要序列化的类型使用序列化属性。一般来说,我通过这样做使其工作:

private byte[] Serialize(object value)
{
    var type = value.GetType();
    var typeModel = RuntimeTypeModel.Default.Add(type, false);

    foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
    {
        typeModel.Add(prop.Name);
    }

    using (var stream = new MemoryStream())
    {
        try
        {
            Serializer.Serialize(stream, value);
            return stream.ToArray();
        }
        catch (Exception ex)
        {
            throw;
        }
    }
}
但是,我有一种类型,
DynamicEntity
(见下文),它对于不会序列化的整个解决方案至关重要。我已经对此做了一些工作,但是我想不出一种方法来让RuntimeTypeModel保存正确的序列化信息。相反,Serialize会在消息中不断抛出InvalidCastException

“无法将“OpenNETCF.ORM.FieldValue”类型的对象强制转换为“System.String”类型。”

以下是相关的类别定义:

public class DynamicEntity
{
    public DynamicEntity();

    public string EntityName { get; set; }
    public FieldCollection Fields { get; }
}

public class FieldCollection : IEnumerable<FieldValue>, IEnumerable
{
    public int Count { get; }

    public object this[string fieldName] { get; set; }

    public void Add(string fieldName);
    public void Add(string fieldName, object value);
    public IEnumerator<FieldValue> GetEnumerator();
}

public class FieldValue
{
    public string Name { get; }
    public object Value { get; set; }
}
公共类动态性
{
公共活力();
公共字符串EntityName{get;set;}
公共字段集合字段{get;}
}
公共类字段集合:IEnumerable,IEnumerable
{
公共整数计数{get;}
公共对象此[string fieldName]{get;set;}
public void Add(字符串字段名);
public void Add(字符串字段名、对象值);
公共IEnumerator GetEnumerator();
}
公共类字段值
{
公共字符串名称{get;}
公共对象值{get;set;}
}

FieldValue通常只保存简单的值—数据库字段可能保存的值。我可以修改上述类的定义(即,我拥有它们),但我不想强制该类型的其他使用者反过来必须引用或使用protobuf。

protobuf net不太喜欢
对象
它想了解模式。这里的一个选项是将FieldValue作为抽象的,带有一个泛型子类
FieldValue
,显式地提供一个不同的子类标识符。这可以通过
[ProtoInclude]
RuntimeTypeModel
实现。然而,我并不清楚消费者的问题是什么,即属性是否是一个问题。你能澄清一下吗?

好吧,最后它肯定没有我希望的那么简单,它也没有我希望的那么健壮,因为我不得不硬编码那些可以工作的类型,但是我正在使用的解决方案有一组有限的类型(无论如何,现在),所以在Marc的间接帮助下,这有点封装古怪,工作:

[ProtoContract]
internal class SerializableDynamicEntity
{
    [ProtoMember(1)]
    public string EntityName { get; set; }

    [ProtoMember(2)]
    public List<SerializableFieldValue> Fields { get; set; }

    public SerializableDynamicEntity()
    {
        Fields = new List<SerializableFieldValue>();
    }

    private SerializableDynamicEntity(string name)
        : this()
    {
        EntityName = name;
    }

    public static explicit operator SerializableDynamicEntity(DynamicEntity de)
    {
        var sde = new SerializableDynamicEntity(de.EntityName);

        foreach (var f in de.Fields)
        {
            sde.Fields.Add(SerializableFieldValue.Create(f));
        }

        return sde;
    }

    public static explicit operator DynamicEntity(SerializableDynamicEntity sde)
    {
        var de = new DynamicEntity(sde.EntityName);

        foreach (var f in sde.Fields)
        {
            de.Fields.Add(f.Name, f.UntypedValue);
        }

        return de;
    }
}

[ProtoContract]
[ProtoInclude(3, typeof(SerializableFieldValue<bool>))]
[ProtoInclude(4, typeof(SerializableFieldValue<int>))]
[ProtoInclude(5, typeof(SerializableFieldValue<double>))]
[ProtoInclude(6, typeof(SerializableFieldValue<string>))]
[ProtoInclude(7, typeof(SerializableFieldValue<DateTime>))]
[ProtoInclude(8, typeof(SerializableFieldValue<long>))]
[ProtoInclude(9, typeof(SerializableFieldValue<short>))]
internal abstract class SerializableFieldValue
{
    public static SerializableFieldValue<T> Create<T>(string name, T value)
    {
        return new SerializableFieldValue<T>()
        {
            Name = name,
            Value = value
        };
    }

    public static SerializableFieldValue Create(FieldValue f)
    {
        var type = f.Value.GetType();

        switch (Type.GetTypeCode(type))
        {
            case TypeCode.Boolean:
                return Create(f.Name, (bool)f.Value);
            case TypeCode.Int32:
                return Create(f.Name, (int)f.Value);
            case TypeCode.Double:
                return Create(f.Name, (double)f.Value);
            case TypeCode.String:
                return Create(f.Name, (string)f.Value);
            case TypeCode.DateTime:
                return Create(f.Name, (DateTime)f.Value);
            case TypeCode.Int64:
                return Create(f.Name, (long)f.Value);
            case TypeCode.Int16:
                return Create(f.Name, (short)f.Value);
            default:
                throw new NotSupportedException();
        }
    }

    [ProtoMember(1)]
    public string Name { get; set; }
    public abstract object UntypedValue { get; set; }
}

[ProtoContract]
internal sealed class SerializableFieldValue<T> : SerializableFieldValue
{
    public SerializableFieldValue()
    {
    }

    [ProtoMember(2)]
    public T Value { get; set; }

    public override object UntypedValue
    {
        get { return Value; }
        set { Value = (T)value; }
    }
}
[协议]
内部类SerializableDynamicEntity
{
[原成员(1)]
公共字符串EntityName{get;set;}
[原成员(2)]
公共列表字段{get;set;}
public SerializableDynamicEntity()
{
字段=新列表();
}
私有SerializableDynamicEntity(字符串名称)
:此()
{
EntityName=名称;
}
公共静态显式运算符SerializableDynamicEntity(DynamicEntity de)
{
var sde=新的SerializableDynamicEntity(de.EntityName);
foreach(de.Fields中的变量f)
{
Add(SerializableFieldValue.Create(f));
}
返回sde;
}
公共静态显式运算符DynamicEntity(SerializableDynamicEntity sde)
{
var de=新的动态性(sde.EntityName);
foreach(sde.字段中的变量f)
{
de.Fields.Add(f.Name,f.UntypedValue);
}
返回de;
}
}
[原始合同]
[ProtoInclude(3,typeof(SerializableFieldValue))]
[ProtoInclude(4,typeof(SerializableFieldValue))]
[ProtoInclude(5,typeof(SerializableFieldValue))]
[ProtoInclude(6,typeof(SerializableFieldValue))]
[ProtoInclude(7,typeof(SerializableFieldValue))]
[ProtoInclude(8,typeof(SerializableFieldValue))]
[ProtoInclude(9,typeof(SerializableFieldValue))]
内部抽象类SerializableFieldValue
{
公共静态SerializableFieldValue创建(字符串名称,T值)
{
返回新的SerializableFieldValue()
{
Name=Name,
价值=价值
};
}
公共静态SerializableFieldValue创建(FieldValue f)
{
var type=f.Value.GetType();
开关(类型.GetTypeCode(类型))
{
大小写类型代码。布尔值:
返回Create(f.Name,(bool)f.Value);
case TypeCode.Int32:
返回Create(f.Name,(int)f.Value);
案例类型代码。双:
返回Create(f.Name,(double)f.Value);
大小写类型代码。字符串:
返回Create(f.Name,(string)f.Value);
案例类型代码.DateTime:
返回Create(f.Name,(DateTime)f.Value);
case TypeCode.Int64:
返回Create(f.Name,(long)f.Value);
case TypeCode.Int16:
返回Create(f.Name,(short)f.Value);
违约:
抛出新的NotSupportedException();
}
}
[原成员(1)]
公共字符串名称{get;set;}
公共抽象对象非类型值{get;set;}
}
[原始合同]
内部密封类SerializableFieldValue:SerializableFieldValue
{
public SerializableFieldValue()
{
}
[原成员(2)]
公共T值{get;set;}
公共重写对象非类型值
{
获取{返回值;}
设置{Value=(T)Value;}
}
}

这样一来,原始的基本代码不需要属性,甚至不需要任何更改,但是需要序列化的特定存储实现可以在内部隐藏这些属性。

挑战在于,这是一个通用的、可扩展的ORM。可以存储到FieldValue中的类型可以是实现者想要存储的任何内容,也可以是为任何可以想象的存储检索的任何内容。我目前正在实现一个云支持的存储,它本身不适合存储逻辑“行”,但我需要时间一致性,所以我要存储一个序列化实体。但是,实体本身是由用户在运行时通过拖放UI生成的。为了让它更有趣,来自它的类型,虽然目前是静态的,但需要保持对任何可能出现的类型的可扩展性。@ctacke老实说,它听起来不像什么东西