Серийный определитель не определен для типа: System.Drawing.Color

77
7

Чтобы уменьшить сетевой трафик, я хочу использовать protobuf-net вместо BinaryFormatter, но произошла следующая ошибка:


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


Применение:


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

спросил(а) 2021-01-25T18:22:10+03:00 5 месяцев назад
1
Решение
100

Он не гарантирует обработку всех известных типов 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 байта на элемент).

ответил(а) 2021-01-25T18:22:10+03:00 5 месяцев назад
77

Итак, что вопрос?


Сериализатор встроенных цветовых классов отсутствует.

Если вы хотите передать цвет по проводу, вам придется сделать это в другом представлении, например, отправив 32-битное целое число для ARGB, что довольно распространено для цвета.


Существует много стандартных способов передачи цвета. Я предлагаю вам придерживаться стандартного способа сделать это, а не пытаться определить свои собственные. Просто придерживайтесь 32-битного целого или 4 байта ARGB.

ответил(а) 2021-01-25T18:22:10+03:00 5 месяцев назад
63

Поскольку я боролся с чем-то подобным все утро, я добавлю, что другой способ хранения Point, Size, Rectangle и Color и т.д. - использовать встроенный конвертер 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 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 и может использоваться для восстановления Точки (и остальных):


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 мне больше нравится хранить/передавать Int, представляющий значение ARGB, но метод строки Invariant тоже хорошо работает, и если цвет имеет именованный цвет, такой как "красный", то 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 вместо вызванной процедуры, но в моем тестовом случае есть несколько точек, прямоугольников и размеров, и я хотел убедиться, что все они обработаны одинаково.


НТН

ответил(а) 2021-01-25T18:22:10+03:00 5 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема