2012-07-05 26 views
0

我目前通過套接字連接接收一個序列化的對象,這工作完美無瑕。我也正在反序列化它。現在,我希望客戶端通過網絡發送多個對象類型(或類)。這個對象是不是很好的練習?另外,還有更好的方法嗎?

這是我如何反序列化我的對象到它的類型「MyClass的」:

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

現在,如果我想獲得超過1種對象類型我既可以做,可以將其轉換爲一個方法任何類型的支持或發送頭將告訴我對象的類型,然後投它。我更喜歡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; 

} 

(我還可以做的是運營商的東西,但是,這將讓我檢查空事後例如)

var MyClass = objectReceived as MyClass; 
var AnotherClass = objectReceived as AnotherClass 

OR我可以實現通過網絡發送的每個對象都會實現的接口,將該對象作爲該接口進行轉換,該接口將返回它的類型,然後進行相應的轉換!

事情是,我已經有了那個工作代碼,但我找不出一個乾淨的方式來編寫該接口。界面的方法應該返回什麼?一種?一個字符串?我真的不知道。這就是爲什麼我告訴自己:嗯,因爲我有工作代碼,如果這是良好的實踐並且易於維護,我不會因爲時間限制而陷入製作界面的麻煩,因爲我現在不知道如何操作界面。

所以這是我的問題:我的方法是正確的/良好的做法?或者界面方法更好?

非常感謝您的幫助!

+1

關於返回值,最理想的情況是,您希望返回一個儘可能緊湊的類型以滿足所需數量的類並支持快速比較(即切換)。 (一個int可能?) – Wug 2012-07-05 14:30:13

+1

出於興趣做這些不同的對象有共同的東西(即所有派生自給定的類型等等)還是它們完全獨立的對象? – Chris 2012-07-05 14:44:57

+0

不,但他們可以,我想要的是他們擁有INTERFACE的共同點=)。感謝你的回答。 – Gaspa79 2012-07-05 14:51:48

回答

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); 
} 

很明顯,你可以通過任何類型(類,如果你喜歡)你喜歡在<>的之間,它會使用該類型來代替。

+0

因爲我不知道這意味着什麼。字面意思是:你失去了我的 thingy =(。謝謝很多,我會研究這個。你有什麼起點,所以我可以學習如何用這樣的方法編碼?我知道如何使用< >運算符,如列表,但我不知道如何編碼它們 – Gaspa79 2012-07-05 14:38:02

+0

'T'是一個通用類型(它可以是任何你想要的類型),所以當你用''調用方法時,你可以想象出'T '一直''MyClass'。看看這裏的介紹:http://www.codeproject.com/Articles/6207/Generics-C – DaveShaw 2012-07-05 14:48:12

+0

OOOOOOOH我看到,T是泛型所有類型派生自?現在我得到一切!您可以在較大和較小的符號之間傳遞實際的類型!然後(T)演員將根據你通過<> thingys的類型變成一個類型轉換!哇!謝謝很多人! – Gaspa79 2012-07-05 14:55:52

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)。

+0

這是一個好主意,並且易於編碼。真的,謝謝! – Gaspa79 2012-07-05 14:39:16

+2

這與我在發表評論時的想法幾乎完全相同(在看到此答案之前)。事實上如此相同,我會拋棄我的評論。 :) +1指出你需要計算出對象是否相同或完全不同,用於打開標題字符串的+1(儘管我並不認爲Damieh說他不喜歡在字符串上切換,但是很高興有了這個)。可悲的是,我的+1按鈕似乎不再工作,所以我不能給這些+1這個答案。 ;-) – Chris 2012-07-05 14:54:06

+0

我剛剛閱讀你的更新答案。枚舉讓它變得更好。我一定會這樣做!如果我能接受這兩個答案,但不幸的是它只讓我接受。我只能贊成這一個。非常感謝! – Gaspa79 2012-07-05 19:44:26

1

您將使用哪種鑄造沒有多大區別。唯一的區別:

x = (Type) deserialized; 

x = deserialized as Type; 

是,如果反序列化的第一個會引發一個InvalidCastException的類型是不是,而第二個將在x返回null。 正如@DaveShaw所解釋的那樣 - 使用泛型是一種非常好的方法,但是如果沒有更好的方法來實現你想要的功能,這取決於你的架構。

+0

是的,我知道演員之間的區別。另外,如果你想進一步:as關鍵字相當於x =反序列化是類型? (type)反序列化:(type)null。雖然很好的答案,我會用daveshaw的說法來使用泛型。 =) – Gaspa79 2012-07-05 14:46:05

相關問題