0

我目前正在通过套接字连接接收序列化对象,这完美无缺。我也在反序列化它。现在,我希望客户端通过网络发送多个对象类型(或类)。

这就是我将我的对象反序列化到它的类型'MyClass'的方式:

var m = new MemoryStream(Convert.FromBase64String(dataReceived));
var b = new BinaryFormatter();
var o = (MyClass)b.Deserialize(m);

现在,如果我想接收超过 1 个对象类型,我可以创建一个可以将其转换为任何支持的类型的方法,或者发送一个标头,告诉我对象的类型然后转换它。我更喜欢第一种方式。

问题是,我当然不能用 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

或者我可以实现一个接口,通过网络发送的每个对象都将实现该接口,将对象转换为该接口,该接口将返回它的类型,然后相应地转换它!

问题是,我已经有了那个工作代码,但是我想不出一个干净的方法来编码那个接口。接口的方法应该返回什么?一种?一个字符串?我真的不知道。这就是为什么我告诉自己:好吧,因为我有工作代码,如果它是好的实践并且易于维护,我不会让自己陷入制作界面的麻烦,因为时间限制我现在不知道该怎么做.

所以这就是我的问题:我的方法是否正确/良好的做法?还是界面方法更好?

非常感谢你们的帮助!!

4

3 回答 3

6

为什么不使用泛型?

您可以创建一个通用的反序列化方法,如下所示:

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);你会让方法认为TMyClass.

想象它这样做:

private MyClass MyDeserialize(String dataReceived)
{
    var m = new MemoryStream(Convert.FromBase64String(dataReceived)); 
    var b = new BinaryFormatter(); 
    return (MyClass)b.Deserialize(m); 
}

显然,您可以在 's 之间传递您喜欢的任何类型(如果您愿意,可以使用类)<>,它将使用该类型。

于 2012-07-05T14:29:05.813 回答
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)。

于 2012-07-05T14:35:54.927 回答
1

您将使用哪种铸件没有太大区别。之间的唯一区别:

x = (Type) deserialized;

x = deserialized as Type;

如果反序列化不是 Type,第一个将引发 InvalidCastException,而第二个将返回 null in x。正如@DaveShaw 解释的那样 - 使用泛型是一种非常好的方法,但如果没有更好的方法来做你想做的事,这取决于你的架构。

于 2012-07-05T14:41:00.387 回答