这个对象是不是很好的练习?还有,有更好的方法吗?

时间:2012-07-05 14:23:38

标签: c# casting

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

这是我将对象反序列化为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 我可以实现一个接口,通过网络发送的每个对象都会实现,将对象转换为接口,然后返回它的类型,然后相应地转换它!

问题是,我已经拥有了这个工作代码,但我无法找到一种简洁的方法来编写该接口。接口的方法应该返回什么?一种?一串?我真的不知道。这就是为什么我告诉自己:好吧,因为我有工作代码,如果这是一个好的做法并且易于维护,我不会因为时间限制而陷入制作我现在不知道如何的界面的麻烦

这就是我的问题:我的方法是正确/良好的做法吗?或者界面方法更好?

非常感谢你的帮助!

3 个答案:

答案 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);时使用泛型,您会认为该方法认为TMyClass

想象一下这样做:

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所解释的那样 - 使用泛型是一种非常好的方法,但如果没有更好的方法来做你想做的事情,这取决于你的架构。