3

为了减少网络流量,我想使用 protobuf-net 来代替BinaryFormatter,但是发生了以下错误:

No serializer defined for type: System.Drawing.Color

WB消息:

[ProtoContract]
[Serializable]
public abstract class WBMessage
{
    [ProtoMember(1)]
    public Color setColor1;

    [ProtoMember(2)]
    public UInt16 userNo;

    public abstract WHITEBOARD_MESSAGE_TYPE MessageType
    {
        get;
    }

    [ProtoMember(3)]
    public string age;

    public enum WHITEBOARD_MESSAGE_TYPE
    {
        enWBBegin,
        enWBLine,
        enWBRectangle,
        enWBRectangleF,
        enWBEllipse,
        enWBEllipseF,
        enWBClearScreen,
        enWBText,
        enWBEnd
    };
}

WBMsgDrawBegin:

[ProtoContract]
[ProtoInclude(1, typeof(WBMessage))]
public class WBMsgDrawBegin : WBMessage
{
    private const WHITEBOARD_MESSAGE_TYPE m_enMsgType =   WHITEBOARD_MESSAGE_TYPE.enWBBegin;
    public override WHITEBOARD_MESSAGE_TYPE MessageType
    {
        get
        {
            return m_enMsgType;
        }
    }

    [ProtoMember(4)]
    public int x;

    [ProtoMember(5)]
    public int y;

    [ProtoMember(6)]
    public bool m_bMouseDown;

    [ProtoMember(7)]
    public string name;
}

用法:

WBMsgDrawBegin item1 = new WBMsgDrawBegin();
item1.setColor1 = Color.AliceBlue;
item1.name = "test";
item1.age = "31";

item1.x = 10998;
item1.y = 10089;

Stream stream = new MemoryStream();
MemoryStream ms = new MemoryStream();
Serializer.SerializeWithLengthPrefix<WBMsgDrawBegin>(ms, item1, PrefixStyle.Base128, 0);
4

3 回答 3

4

它不能保证处理所有已知的 BCL 类型,尤其是来自图形库之类的东西,这些类型并非在所有平台上都受支持。我会推荐:

public Color Foo {get;set;}

[ProtoMember(n, DataFormat=DataFormat.Fixed)]
private int FooSerialized {
    get { return Foo.ToArgb(); }
    set { Foo = Color.FromArgb(value); }
}

这会将其序列化为固定的 4 字节块。如果你有很多颜色属性,你也可以使用“代理”来做一些非常相似的事情(更少的代码,但每个项目多出 2 个字节)。

于 2012-06-10T08:41:39.033 回答
2

那么问题是什么?

内置颜色类没有序列化程序。

如果您想通过线路传达颜色,您将不得不以其他一些表示形式进行,例如为 ARGB 发送一个 32 位整数,这对于颜色来说是非常常见的做法。

有许多传达颜色的标准方法。不过,我建议您坚持使用标准方式,而不是尝试定义自己的方式。只需坚持使用 32 位整数或 4 字节 ARGB。

于 2012-06-10T06:07:44.897 回答
1

由于我整个早上都在与类似的东西搏斗,所以我要补充一点,另一种存储点、大小、矩形和颜色等的方法是使用 NET 的内置转换器。代码在 VB 中,但你应该足够好地理解漂移:

Imports System.Drawing
Imports System.ComponentModel

Private Function GetInvariantString(ByVal v As Object) As String
    Dim conv As TypeConverter = TypeDescriptor.GetConverter(v.GetType)
    Dim t As System.Type = v.GetType

    ' at least in VB '=' and 'Is' are not defined for Boolean 
    '  and System.Type so I cant find a way to word the Case 
    '  test so, it's inverted...only one Case can be true anyway
    Select Case True
        ...
        Case t Is GetType(Drawing.Point)
            Return conv.ConvertToInvariantString(v)

        Case t Is GetType(Drawing.Size)
            Return conv.ConvertToInvariantString(v)

        Case t Is GetType(Drawing.Color)
            Return conv.ConvertToInvariantString(v)

        Case Else
            Throw New ArgumentException("Unknown Type " & v.type.ToString)
    End Select

End Function

的简单方法myPoint.ToString将返回类似{X=11 Y=156}但并不总是FromString对此处处理的类型的补充方法。 ConvertToInvariantString返回11, 156并可用于重构 Point(和其余部分):

Private Function TypeFromInvariantString(ByVal pbnString As String,  _
            ByVal ttype As Type) As Object

    ' same thing...
    Select Case True
        Case ttype Is GetType(Point)
            Return TypeDescriptor.GetConverter(GetType(Drawing.Point)).ConvertFromInvariantString(pbnString)

        Case ttype Is GetType(Size)
            Return TypeDescriptor.GetConverter(GetType(Drawing.Size)).ConvertFromInvariantString(pbnString)

        Case ttype Is GetType(Color)
            Return TypeDescriptor.GetConverter(GetType(Drawing.Color)).ConvertFromInvariantString(pbnString)

        Case Else
            Throw New ArgumentException("Unknown Type " & ttype.ToString)
    End Select


End Function

矩形、SizeF 等(甚至是字体)都可以以相同的方式处理。就我个人而言,Color我更喜欢存储/传递一个表示 ARGB 值的 Int,但 Invariant 字符串方法也很有效,如果颜色是像“Red”这样的命名颜色,那么Red就是返回/序列化的所有内容。用法:

' serializer version
<ProtoMember(6)> _
Private Property PBNImgPoint() As String
    Get
        Return GetInvariantString(_ImgPoint)
    End Get
    Set(ByVal value As String)
        _ImgPoint = TypeFromInvariantString(value, GetType(Point))
    End Set
End Property

' method used in code/program....
Friend Property ImgPoint() As Point
    Set(ByVal value As Point)
        _ImgPoint = value
    End Set
    Get
        Return _ImgPoint
    End Get
End Property

显然,转换可以在每个 Getter/Setter 而不是调用的过程中发生,但我的试点/测试用例有多个点、矩形和大小,我想确保它们都得到相同的处理。

高温高压

于 2013-09-20T19:19:28.193 回答