我目前正在使用clrmq绑定为ZeroMQ设计C#中的网络包装器。
我的问题是我正在尝试一种方法来进行反序列化和序列化 透明;也就是说,网络包装器可以在不知道或关心其类型的情况下将任何对象作为字节进行传输,并且可以在另一端反序列化为正确的类型。
我有一个类heirachy如下
public interface ITransmission
{
Type Type { get; }
}
public abstract class Transmission<T> : ITransmission
{
public Type Type { get { return typeof(T); } }
}
想法是序列化已实现传输类型的对象;传输 它们在clrmq上作为字节并在另一端反序列化
我理想的解决方案
目前人们正在使用或正在做什么来透明地解决序列化和反序列化的问题?在某些时候速度将是一个因素,但在这个时候,我只是想找出选项是什么。
这里隐含的限制是网络库需要引用包含要传输的类型的所有程序集吗?
此外,另一个问题是,这是一种可行的方法,还是服务器和客户端是否应该从强制类型中获取?
感谢阅读。
答案 0 :(得分:1)
我能够在使用Reflection的在线多人游戏中成功完成此操作,这可能会根据您的要求满足您的需求。
这是一个描述我是如何做到这一点的链接:http://www.gamedev.net/topic/436066-please-critique-my-serialization-system-net--reflection/
简而言之,这就是我如何序列化/ Derialized我的数据:我创建了一个名为'GameMessage'的类,它使用反射来序列化/反序列化自身。然后每个消息类型都只是从这个类继承而且神奇地有一个ToByte()函数和接受byte []的构造函数为它工作:
public class GameMessage
{
private static int SortFieldInfo(FieldInfo left, FieldInfo right)
{
if (left.Equals(right))
{
return 0;
}
if (right.Name == "ID")
return 1;
else if (right.FieldType.Name == "String")
return -1;
else
return 0;
}
public GameMessage(){}
public GameMessage(byte[] data)
{
List<byte> bytes = new List<byte>();
List<FieldInfo> info = new List<FieldInfo>(this.GetType().GetFields());
info.Sort(SortFieldInfo);
int idx = 0;
for (int i = 0; i < info.Count; i++)
{
if (info[i].FieldType.Name == "String")// is string)
{
string value;
UInt16 size;
if (i != info.Count - 1)
{
size = BitConverter.ToUInt16(data, idx);
idx += 2;
value = ASCIIEncoding.ASCII.GetString(data, idx, size);
idx += size;
}
else
{
value = ASCIIEncoding.ASCII.GetString(data, idx, data.Length - idx);
idx += data.Length - idx;
}
info[i].SetValue(this,value);
}
else
{
if (info[i].Name != "ID")
{
Type[] types = new Type[2] { data.GetType(), idx.GetType() };
object[] values = new object[2] { data, idx };
info[i].SetValue(this, typeof(BitConverter).GetMethod("To" + info[i].FieldType.Name, types).Invoke(null, values));
idx += Marshal.SizeOf(info[i].FieldType);
}
else
{
idx += sizeof(ID);
}
}
}
}
public byte[] ToByte()
{
List<byte> bytes = new List<byte>();
List<FieldInfo> info = new List<FieldInfo>(this.GetType().GetFields());
info.Sort(SortFieldInfo);
for(int i=0;i<info.Count;i++)
{
if (info[i].FieldType.Name == "String")
{
if (i != info.Count - 1)
{
bytes.AddRange(BitConverter.GetBytes(((UInt16)((string)info[i].GetValue(this)).Length)));
}
bytes.AddRange(ASCIIEncoding.ASCII.GetBytes((string)info[i].GetValue(this)));
}
else
{
bytes.AddRange((byte[])typeof(BitConverter).GetMethod("GetBytes", new Type[] { info[i].FieldType }).Invoke(null, new object[] { info[i].GetValue(this) }));
}
}
return bytes.ToArray();
}
}
答案 1 :(得分:1)
用户dferraro的解决方案很好。但我认为现在可以通过C#中的序列化更好地实现很多。我强烈建议您将 ZeroMQ 与用于序列化和消息传递组件的Google Protobuf 框架配对。
查看Protobuf here的.NET实现。我不会详细介绍它的实现方面,因为它已经很好地记录了,并且StackOverflow上有很多关于它的好问题。事实上,Protobuf的C#实现的作者 - Marc Gravell - 经常在SO上闲置,并会回复protobuf-net标记的任何问题。