2011-02-10 7 views
2

uint16、uint32、int32などをネットワークバイトオーダーに変換する関数がいくつかあります。さまざまなタイプの構造体のフィールドを動的にネットワークバイトオーダーに変換する必要がありますが、どうすればいいですか?C#でフィールドを動的に変換する

eg, structType1, structType2, structType3 

void toNetworkByte(what type to pass so that it could accept structType1,2 and 3?) 
{ 
    //getfieldInfo for all the fields in the struct 

    //if it is type uint16, call convertUINT16 
    // elseif it is type uint32, convertUINT32 
    // elseif it is typeof struct, call toNetworkByte again 

} 

ありがとう。

答えて

1

これは、メソッドオーバーロードの主要なシナリオです。同じ名前の3つの異なるメソッドを持つだけですが、それぞれ異なる型のパラメータを受け取ります。コンパイラは、渡す引数の型に応じて、呼び出す必要のあるものを自動的に特定します。プロセスはプログラマにとって完全に透過的であり、構文は常に同じです。例:それ以外の場合は

void toNetworkByte(structType1 arg) 
{ 
    // do something for structType1 
} 

void toNetworkByte(structType2 arg) 
{ 
    // do something different for structType2 
} 

void toNetworkByte(structType3 arg) 
{ 
    // do something different for structType3 
} 

、あなたが共有から同じインタフェースを変換するために必要なすべてのタイプの場合、あなたはgeneric methodを使用することができます。

void toNetworkByte<T>(T arg) where T : IMyStruct 
{ 
    // place your conversion code here 
} 
+0

あなたはまた、それはあなたの状況に適用された場合にのみ、構造体(値型)を許可するようにTを制約することができます - toNetworkByte (T引数)where T:struct – jeffora

+0

@jeffora:あなたは確かにすることができます。残念ながら、ジェネリックメソッドに*特定の* struct型だけを受け入れるように制約する方法はないので、私はそれについて言及していませんでした。私は私の答えを更新します。 –

+0

もちろん。それは特定の構造体の場合にのみ一般的ではありません;-) – jeffora

1

は、たぶん私は質問を読み違えていますが、それはあなたが3つの構造体の型のいずれかを受け入れることができるようにしたいように、その中のフィールドの上に反映聞こえる:次の例では、すべての構造体がIMyStructインターフェイスを実装を前提としていその型に基づいて各フィールドに要素を加えますか?

これが当てはまる場合、オブジェクトを渡すのはなぜですか?あなただけの構造体にする方法を制限したい場合(@jefforaは上記の言ったように)、あなたは可能性

void toNetworkByte<T>(T arg) where T : struct { 
    //getfieldInfo for all the fields in the struct 

    //if it is type uint16, call convertUINT16 
    // elseif it is type uint32, convertUINT32 
    // elseif it is typeof struct, call toNetworkByte again 
} 

明らかに人々が記載されている3の1だけではなく、で任意の構造体を、あなたのメソッドを呼び出すことができるようになりますと言います上記。それを制限することが本当に重要なのであれば、@Cody Greyのように、それぞれのタイプ(潜在的なコードの多く)にオーバーロードが必要になるでしょう。

+0

'オブジェクト'を渡すのは間違いです。あなたはいくつかの異なる値の型を渡す必要がある場合は、オブジェクトとの間でボクシングによって発生したパフォーマンスのペナルティを受ける理由は絶対にありません。これは、オーバーロードされたメソッドとジェネリックのためのものです。あなたの答えにはいくつかの良い情報がありますが、これはそうではありません。 –

+0

パラメータを参照パラメータとして宣言せずに元の構造体の値を更新することはできますか? –

+0

はい、Objectとして渡すと、構造体がボックス化されます。このメソッドを何度も呼び出す予定がある場合は、パフォーマンス重視のコンテキストでは、間違いなくオブジェクトを使用しないでください。しかし、ジェネリック版はボクシングを避ける必要があります。 –

0
void toNetworkByte(object arg) 
{ 
    if (arg is Int32) 
{ 
} 
else if (arg is Double) 
{ 
} 
else if (// is valueType 
{ 
} 
} 

は常にオプション:)

+0

多分私はここで構文に失敗しました。 Cody GrayとAdam Rackisのソリューションははるかに優れています。これはちょうど参考です –

0

1)構造体は値によって渡されています。メソッドのフィールドの値を変更した場合、渡された元の構造体では更新されません。変更された構造体を返すか、refパラメータとして宣言する必要があります。

2)ボクシングはパフォーマンスはあまり良くありませんが、それほど悪くはありません。しかし、重要なことは、(私が見つけたものから)働くために反射を使って値を設定するためにボクシングを使う必要があるということです。 FieldInfo.SetValue(object、object)は、オブジェクトをパラメータとして取り、構造体を囲み、ボックス化された構造体の値を設定しますが、元の構造体は更新されません。

結果:

a: StructA[S1=0x1122, I1=0x11223344] 
a: StructA[S1=0x2211, I1=0x44332211] 

ここで動作するコードです:

class Test 
{ 
    public static void Convert<T>(ref T arg) 
    { 
     object o = arg; // box so SetValue will work 
     Type argType = arg.GetType(); 
     foreach (FieldInfo fi in argType.GetFields()) 
     { 
      if (fi.FieldType == typeof(System.Int32)) 
       fi.SetValue(o, IPAddress.HostToNetworkOrder((int)fi.GetValue(o))); 
      else if (fi.FieldType == typeof(System.Int16)) 
       fi.SetValue(o, IPAddress.HostToNetworkOrder((short)fi.GetValue(o))); 
     } 
     arg = (T)o; // unbox and set value of ref parameter 
    } 

    public static void RunTest() 
    { 
     StructA a = new StructA() { I1 = 0x11223344, S1 = 0x1122 }; 
     Console.WriteLine("a: {0}", a); 
     Convert(ref a); 
     Console.WriteLine("a: {0}", a); 
    } 
} 

public struct StructA 
{ 
    public short S1; 
    public int I1; 
    public override string ToString() 
    { 
     return string.Format("StructA[S1=0x{0:X4}, I1=0x{1:X8}]", S1, I1); 
    } 
} 

public struct StructB 
{ 
    public short S2; 
    public int I2; 
    public override string ToString() 
    { 
     return string.Format("StructB[S2=0x{0:X4}, I2=0x{1:X8}]", S2, I2); 
    } 
} 
関連する問題