0

現在、ソケット接続を介してシリアル化されたオブジェクトを受信して​​いますが、これは問題なく動作します。私もそれをうまくデシリアライズしています。ここで、クライアントにネットワーク経由で複数のオブジェクト タイプ (またはクラス) を送信してもらいたいと考えています。

これは、オブジェクトをタイプ「MyClass」に逆シリアル化する方法です。

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

ここで、複数のオブジェクト型を受け取りたい場合は、サポートされている任意の型にキャストできるメソッドを作成するか、オブジェクトの型を教えてからキャストするヘッダーを送信できます。私は最初の方法を好みます。

もちろん、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 演算子を使用して何かを行うこともできますが、後で null をチェックする必要があります。たとえば)

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

明らかに、 の間で任意のタイプ (必要に応じてクラス) を渡すことができ、<>代わりにそのタイプが使用されます。

于 2012-07-05T14:29:05.813 に答える
2

潜在的に、あなたの問題の原因は、1 つの方法であまりにも多くのことをしようとしていることにあると思います。メソッドがすべての異なるタイプのオブジェクトで同じことを行っているか (この場合、それらはすべて同じインターフェイスを共有し、それらすべてをそれにキャストする必要があります)、または私が推測するように、それぞれで異なることを行っています。その場合、すべてのロジックを 1 つのメソッドまたは 1 つのクラスに結合することはお勧めできません。

したがって、次のようなメソッドがある場合:

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 コードは次のようになります。

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;

1 つ目は、deserialized が Type でない場合に InvalidCastException を発生させ、2 つ目は で null を返すことxです。@DaveShawが説明したように、ジェネリックを使用することは非常に優れたアプローチですが、必要なことを行うためのより良い方法がない場合は、アーキテクチャに依存します。

于 2012-07-05T14:41:00.387 に答える