问题
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