No serializer defined for type: System.Drawing.Color

冷暖自知 提交于 2019-12-23 17:16:42

问题


In order to decrease the network traffic, I want to use protobuf-net to instead of the BinaryFormatter, But the following error happened:

No serializer defined for type: System.Drawing.Color

WBMessage:

[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;
}

Usage:

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);

回答1:


It doesn't guarantee to handle every known BCL type, especially from things like graphics libraries, that are not supported over all platforms. I would recommend:

public Color Foo {get;set;}

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

which will serialize it as a fixed 4-byte chunk. If you have lots of color properties, you could also use a "surrogate" to do something very similar (less code, but an extra 2 bytes per item).




回答2:


So what's the question?

There is no serializer for the built-in color classes.

If you want to communicate color over the wire, you are going to have to do so in some other representation, such as sending a 32-bit integer for ARGB, which is pretty common practice for color.

There are many standard ways of communicating color. I suggest you stick to a standard way of doing so rather than trying to define your own, though. Just stick with a 32-bit integer or 4 bytes ARGB.




回答3:


Since I was wrestling with something similar all morning, I'll add that another way to store Point, Size, Rectangle and Color etc is to use NET's built in converter. The code is in VB, but you should get the drift well enough:

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

The simple approach of myPoint.ToString will return something like {X=11 Y=156} but there is not always a complementary FromString method for the Types being dealt with here. ConvertToInvariantString returns 11, 156 and can be used to reconstitute the Point (and the rest):

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

Rectangles, SizeF and the like (even Fonts) can all be handled the same way. Personally, for Color I rather like storing/passing an Int representing the ARGB value, but the Invariant string method works well too, and if the color is a named color like "Red" then Red is all that is returned/serialized. Usage:

' 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

Obviously, the conversion can happen in each Getter/Setter instead of a called procedure, but my pilot/test case has multiple Points, Rectangles and Sizes and I wanted to make sure they all got handled the same.

HTH



来源:https://stackoverflow.com/questions/10966495/no-serializer-defined-for-type-system-drawing-color

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!