2009-07-07 15 views
0

で参照型と値型と奇妙な何かを発見した(少なくとも私に:-))私はデモの方法に取り組んでいたジェネリック

enter code here class Program 
{ 
    public void AnotherSwap<T>(T a, T b) 
    { 
     T temp; 
     temp = a; 
     a = b; 
     b = temp; 

     Console.WriteLine(a); 
     Console.WriteLine(b); 

    } 


    public void swap<T>(T a, T b) where T : MyInt // Passing without ref 
    { 
     object temp; 
     temp = a.MyProperty; 
     a.MyProperty = b.MyProperty; 
     b.MyProperty = (int)temp; 

     Console.WriteLine(a.MyProperty); 
     Console.WriteLine(b.MyProperty); 



    } 

    static void Main(string[] args) 
    { 
     Program p = new Program(); 
     MyInt a = new MyInt() { MyProperty = 10 }; 
     MyInt b = new MyInt() { MyProperty = 20 }; 
     p.swap<MyInt>(a, b); 
     Console.WriteLine(a.MyProperty); // changed values get reflected 
     Console.WriteLine(b.MyProperty); // changed values get reflected 

     Console.WriteLine("Another Swap"); 
     object x = 10; 
     object y = 20; 
     p.AnotherSwap(x, y); 

     Console.WriteLine(x); // changed values are not getting reflected 
     Console.WriteLine(y); // changed values are not getting reflected 

     Console.ReadKey(); 


    } 
    public class MyInt 
    { 
     public int MyProperty { get; set; } 

    } 




} 

ここで私は私の避難所ものの、)(スワップを呼び出しています変更された値は自動的に反映されます(p.swap(a、b)のように); aとbはMyintのインスタンスなので、デフォルトではref ...と解釈されます) しかし同じAnotherswap()と一緒に起こるはずです。ここでもオブジェクトx、yを渡していますが、値はMain()に反映されません。現在は値型として動作しています。 誰かが私の理解が間違っているところを説明することができます。 もしあなたがもっと詳しい情報を知りたいのなら教えてください。

答えて

1

MyInt型をObjectとしてキャストすると、val型としてキャストされます。オブジェクトは、valとrefの両方を表現しているので、参照のように扱うことはできません。refで明示的に渡す必要があります。

intはオブジェクトとしてキャストでき、それでもvalとして扱われます。 stringはオブジェクトとしてキャストでき、valとして扱われます。通常はref型になります。

AnotherSwapを実行してMyIntとしてTを渡した場合、以前と同じ結果が得られます。オブジェクトで元のスワップアルゴリズムを呼び出した場合、後者と同じ出力が得られます。

+0

クリス、感謝します。 – Wondering

1

オブジェクトの第2セット[object x = 1]は、初期化時にintに割り当てられているため、値型のintに変換されるため、値型のintとして扱われます。

次のスニペットを実行すると、私の意見が表示されます。

object test = 1; 
Console.Writeline(test.GetType()); 

returns: "typeof (Int32)" 

ので、あなたのobjectのタイプは、値型であるが、もはやオブジェクトのInt32ではありません。

object test = 1; 
Console.Writeline(test.GetType().IsByRef); 

returns: "false" 
+0

IsByRefは、型が参照型かどうかのテストではありません。パラメータ型が*参照によって渡されたかどうかを調べるために使用されます。彼らは非常に異なるものです。 typeof(オブジェクト).IsByRefはまだfalse ... –

+0

ありがとう、それを知らなかった。 Typeクラスの下でこのプロパティを公開するのは直感的ではありません。Reflectionの名前空間の一部ではないはずです。 –

3

ご質問は誤解を招く、と答えは実際よりも簡単です:

あなたのスワップ機能では、これらのクラスでMYPROPERTYプロパティの値ではなく、実際のクラス自体を交換しています。これはMyIntクラスに "Name"などと呼ばれる別のプロパティがあると簡単に証明されます。スワップを呼び出した後、Nameプロパティが変更されていないことがわかります。

AnotherSwapで何も起こっていないのは、refで型を渡すことがないからです。そのため、関数内のオブジェクトのポインタに対して実行する代入は、元のオブジェクトのポインタを呼び出し元の視点。

他の何かを考慮する必要がありますあなたがオブジェクトに10になっているとき、あなたは実際にオブジェクトをボクシングしている、それはあなたが覚えておく必要があります。参照型と値型で異なる振る舞いをするジェネリックを書くときは、参照型は "where T:class"、値型は "where T:struct"を使用します。しかし、2つの関数の名前は同じにすることはできません。

関連する問題