我正在通过套接字连接接收序列化对象,这完美无瑕。我也很好地反序列化它。现在,我希望客户端通过网络发送多个对象类型(或类)。
这是我将对象反序列化为Type'MyClass'的方式:
var m = new MemoryStream(Convert.FromBase64String(dataReceived));
var b = new BinaryFormatter();
var o = (MyClass)b.Deserialize(m);
现在,如果我想要接收多于一个对象类型,我可以创建一个可以将其转换为任何支持类型的方法,或者发送一个标题,告诉我该对象的类型然后将其强制转换。我更喜欢 FIRST 方式。
问题是,当然,我无法使用GetType()进行转换,并且使用name属性会导致出现一些我不喜欢的字符串切换。所以我决定我可以这样做:
object objectReceived = b.Deserialize(m);
if(o is MyClass){
MyClass myClass = (MyClass) objectReceived;
}
else if (o is AnotherClass){
AnotherClass myOtherClass = (AnotherClass) objectReceived;
}
(我也可以使用as运算符执行某些操作,但这会让我在之后检查空值。例如)
var MyClass = objectReceived as MyClass;
var AnotherClass = objectReceived as AnotherClass
OR 我可以实现一个接口,通过网络发送的每个对象都会实现,将对象转换为接口,然后返回它的类型,然后相应地转换它!
问题是,我已经拥有了这个工作代码,但我无法找到一种简洁的方法来编写该接口。接口的方法应该返回什么?一种?一串?我真的不知道。这就是为什么我告诉自己:好吧,因为我有工作代码,如果这是一个好的做法并且易于维护,我不会因为时间限制而陷入制作我现在不知道如何的界面的麻烦
这就是我的问题:我的方法是正确/良好的做法吗?或者界面方法更好?
非常感谢你的帮助!
答案 0 :(得分:6)
为什么不使用Generics?
您可以创建一个通用的反序列化方法,如下所示:
private T MyDeserialize<T>(String dataReceived)
{
var m = new MemoryStream(Convert.FromBase64String(dataReceived));
var b = new BinaryFormatter();
return (T)b.Deserialize(m);
}
任何人都称之为:
MyClass myClassInstance = MyDeserialize<MyClass>(dataReceived);
<强>泛型强>
当您致电MyDeserialize<MyClass>(dataReceived);
时使用泛型,您会认为该方法认为T
为MyClass
。
想象一下这样做:
private MyClass MyDeserialize(String dataReceived)
{
var m = new MemoryStream(Convert.FromBase64String(dataReceived));
var b = new BinaryFormatter();
return (MyClass)b.Deserialize(m);
}
显然你可以在<>
之间传递你喜欢的任何类型(如果你愿意的话),它会使用那种类型。
答案 1 :(得分:2)
我认为,问题的根源可能是你试图在一种方法中做太多事情。要么你的方法对所有不同类型的对象做同样的事情(在这种情况下,它们应该共享相同的接口,你应该将它们全部投射到那个),或者,正如我怀疑的那样,你正在做各自不同的事情。在这种情况下,将所有逻辑组合成一个方法,甚至是一个类,这是不好的做法。
所以,如果你有这样的方法:
private void processObject(MyClass obj) { //... }
private void processObject(AnotherClass obj) { //... }
然后,在反序列化对象的方法中,您只需从消息头中检查类名,然后调用正确的方法:
switch(className)
{
case ClassNameEnum.MyClass: processObject((MyClass)b.Deserialize(m)); break;
case ClassNameEnum.AnotherClass: processObject((AnotherClass)b.Deserialize(m)); break;
}
正如我在本例中所示,使用枚举比使用字符串指定消息头中的类型更好。它是更小的数据,更快的比较,并且不允许拼写错误。如果你确实想要使用字符串以便消息更具可读性,那很好,但是你应该对字符串使用常量。
使用泛型方法反序列化对象是一个很好的建议,在这种情况下,切换代码如下所示:
switch(className)
{
case ClassNameEnum.MyClass: processObject(Deserialize<MyClass>(m)); break;
case ClassNameEnum.AnotherClass: processObject(Deserialize<AnotherClass>(m)); break;
}
然而,这样做并没有真正减轻任何事情。您仍然需要为每种类型添加单独的case
语句。如果你想保持强类型,没有神奇的子弹可以摆脱这种额外的编码。转换的全部内容是通知编译器您在编译时使用的类型。如果有某种方法将它转换为在运行时确定的类型,那将完全没有意义。如果你不关心强类型的优点,你可以把它变成一个dynamic
变量,在这种情况下你可以使用任何类型而不需要它(这需要.NET 4)。
答案 2 :(得分:1)
你将使用哪种铸造没有太大区别。唯一的区别是:
x = (Type) deserialized;
和
x = deserialized as Type;
如果反序列化不是Type,第一个将引发InvalidCastException,而第二个将在x
中返回null。
正如@DaveShaw所解释的那样 - 使用泛型是一种非常好的方法,但如果没有更好的方法来做你想做的事情,这取决于你的架构。