使用 protobuf-net 基于类型变量动态反序列化 class
Dynamically deserialize a class based on a type variable with protobuf-net
我正在尝试创建一个标准化的事件消息传递系统(用于我的游戏服务器和客户端),该系统使用 protobuf-net 通过 UDP 套接字发送数据以实现快速和最佳的数据传输。
目前我正在尝试发送事件 class,目前可能是 PlayerIntentEvent
class 或 OnConnectionEvent
class (存在更多事件,这些只是一个例子)。
我正在发送一个 byte[],其中第一个字节表示事件 class(用于反序列化),byte[] 的其余部分是 class 本身,序列化为protobuf网。这部分工作正常。我的问题在接收部分。 我想根据类型变量动态反序列化 class。
经过一周的搜索和尝试不同的事情后,我找不到这样做的方法。
我当前的设置:
事件类型的常量:
public static class EventTypes {
public static byte OnConnection = 1;
public static byte OnError = 2;
public static byte OnPlayerIntent = 3;
}
服务器的事件映射:
public static class Constants {
public static Dictionary<byte, Type> EventDataCastDictionary = new Dictionary<byte, Type> {
{ EventTypes.OnConnection, null },
{ EventTypes.OnPlayerIntent, typeof (PlayerIntentEvent) }
};
public static readonly IPEndPoint ClientEndPoint = new IPEndPoint(IPAddress.Any, 0);
public static readonly IPEndPoint ServerEndPoint = new IPEndPoint(IPAddress.Any, 9423);
}
出于测试目的,我创建了一个仅将 PlayerIntentEvents 发送到服务器的发送器方法:
public void SendPlayerIntent(PlayerIntentEvent packet) {
try {
byte[] bytes;
using (MemoryStream stream = new MemoryStream()) {
stream.WriteByte(EventTypes.OnPlayerIntent);
ProtoBuf.Serializer.Serialize<PlayerIntentEvent>(stream, packet);
bytes = stream.ToArray();
}
//client is an instance of UdpClient
client.Send(bytes, bytes.Length, serverEndPoint);
} catch (Exception err) {
throw err;
}
}
我的服务器接收方:
using System;
using System.IO;
using System.Net.Sockets;
using System.Threading.Tasks;
using ProtoBuf;
abstract class UdpBase {
protected UdpClient Client;
protected UdpBase() {
Client = new UdpClient();
}
public async Task<Received> Receive() {
var receivedStream = await Client.ReceiveAsync();
NetworkPacket networkPacket = new NetworkPacket();
object packet = null;
//Getting the class type from the first byte of the array
Type eventType = Constants.EventDataCastDictionary[receivedStream.Buffer[0]];
//----PROBLEM
//Here I am reading only the class
using (var stream = new MemoryStream(receivedStream.Buffer, 1, receivedStream.Buffer.Length - 1)) {
//I want to put a type from my mapping in place of the ?????*
//I have tried using eventType variable, but the code does not compile
packet = Serializer.Deserialize<?????*>(stream);
}
//----END OF PROBLEM
//The return statement is not finished
return new Received();
}
}
更新:
使用David修改后开始接收
Exception thrown: 'ProtoBuf.ProtoException' in protobuf-net.dll
Exception thrown: 'ProtoBuf.ProtoException' in mscorlib.dll
更新 2:
我的事件 class 缺少默认的无参数构造函数。现在一切正常,即使没有 Convert.ChangeType
。 :)
您可以使用 non-generic overload 并转换结果:
Type eventType = Constants.EventDataCastDictionary[receivedStream.Buffer[0]];
using (var stream = new MemoryStream(receivedStream.Buffer, 1,
receivedStream.Buffer.Length - 1)) {
packet = Convert.ChangeType(Serializer.Deserialize(eventType, stream),
eventType);
}
我正在尝试创建一个标准化的事件消息传递系统(用于我的游戏服务器和客户端),该系统使用 protobuf-net 通过 UDP 套接字发送数据以实现快速和最佳的数据传输。
目前我正在尝试发送事件 class,目前可能是 PlayerIntentEvent
class 或 OnConnectionEvent
class (存在更多事件,这些只是一个例子)。
我正在发送一个 byte[],其中第一个字节表示事件 class(用于反序列化),byte[] 的其余部分是 class 本身,序列化为protobuf网。这部分工作正常。我的问题在接收部分。 我想根据类型变量动态反序列化 class。
经过一周的搜索和尝试不同的事情后,我找不到这样做的方法。
我当前的设置:
事件类型的常量:
public static class EventTypes {
public static byte OnConnection = 1;
public static byte OnError = 2;
public static byte OnPlayerIntent = 3;
}
服务器的事件映射:
public static class Constants {
public static Dictionary<byte, Type> EventDataCastDictionary = new Dictionary<byte, Type> {
{ EventTypes.OnConnection, null },
{ EventTypes.OnPlayerIntent, typeof (PlayerIntentEvent) }
};
public static readonly IPEndPoint ClientEndPoint = new IPEndPoint(IPAddress.Any, 0);
public static readonly IPEndPoint ServerEndPoint = new IPEndPoint(IPAddress.Any, 9423);
}
出于测试目的,我创建了一个仅将 PlayerIntentEvents 发送到服务器的发送器方法:
public void SendPlayerIntent(PlayerIntentEvent packet) {
try {
byte[] bytes;
using (MemoryStream stream = new MemoryStream()) {
stream.WriteByte(EventTypes.OnPlayerIntent);
ProtoBuf.Serializer.Serialize<PlayerIntentEvent>(stream, packet);
bytes = stream.ToArray();
}
//client is an instance of UdpClient
client.Send(bytes, bytes.Length, serverEndPoint);
} catch (Exception err) {
throw err;
}
}
我的服务器接收方:
using System;
using System.IO;
using System.Net.Sockets;
using System.Threading.Tasks;
using ProtoBuf;
abstract class UdpBase {
protected UdpClient Client;
protected UdpBase() {
Client = new UdpClient();
}
public async Task<Received> Receive() {
var receivedStream = await Client.ReceiveAsync();
NetworkPacket networkPacket = new NetworkPacket();
object packet = null;
//Getting the class type from the first byte of the array
Type eventType = Constants.EventDataCastDictionary[receivedStream.Buffer[0]];
//----PROBLEM
//Here I am reading only the class
using (var stream = new MemoryStream(receivedStream.Buffer, 1, receivedStream.Buffer.Length - 1)) {
//I want to put a type from my mapping in place of the ?????*
//I have tried using eventType variable, but the code does not compile
packet = Serializer.Deserialize<?????*>(stream);
}
//----END OF PROBLEM
//The return statement is not finished
return new Received();
}
}
更新:
使用David修改后开始接收
Exception thrown: 'ProtoBuf.ProtoException' in protobuf-net.dll
Exception thrown: 'ProtoBuf.ProtoException' in mscorlib.dll
更新 2:
我的事件 class 缺少默认的无参数构造函数。现在一切正常,即使没有 Convert.ChangeType
。 :)
您可以使用 non-generic overload 并转换结果:
Type eventType = Constants.EventDataCastDictionary[receivedStream.Buffer[0]];
using (var stream = new MemoryStream(receivedStream.Buffer, 1,
receivedStream.Buffer.Length - 1)) {
packet = Convert.ChangeType(Serializer.Deserialize(eventType, stream),
eventType);
}