2010-01-20 80 views
4

我不是socket編程老手,所以在分析代碼,我在一個數據庫API發現我碰到這個代碼就通過引用傳遞沒有ref關鍵字

public static void WriteInt(int i, NetworkStream bufOutputStream) 
    { 
     byte[] buffer = new byte[IntSize]; 
     WriteInt(i, buffer, 0); 
     bufOutputStream.Write(buffer, 0, buffer.Length); 
    } 

    public static void WriteInt(int i, byte[] byte_array, int pos) 
    { 

     byte_array[pos] =(byte)(0xff & (i >> 24)); byte_array[pos+1] = (byte)(0xff & (i >> 16)); byte_array[pos+2] = (byte)(0xff & (i >> 8)); byte_array[pos+3] = (byte)(0xff & i); 
    } 

我瞭解位移了我不明白的是'緩衝區'var在參數中沒有任何參考或者沒有返回時如何保持獲得值。該位移是以某種方式編輯緩衝區的實際值?

+0

另請參閱http://stackoverflow.com/questions/2058161/do-you-need-the-ref-or-out-parameter/2058320#2058320 – 2010-01-20 19:28:44

回答

20

你的困惑是很常見的一種。要點是要認識到「參考類型」和「經過參考」(ref鍵盤)是完全獨立的。在這個特定的情況下,因爲byte[]是一個引用類型(就像所有的數組一樣),這意味着當你傳遞它時不會複製該對象,因此你總是指向同一個對象。

我強烈建議您閱讀喬恩斯基特對Parameter passing in C#優秀文章,並都應該很清楚......

+1

簡單而有效,謝謝。 – jtzero 2010-01-20 16:58:53

5

因爲數組是不是一個值類型,這是一個引用類型。對堆的位置的引用是按值傳遞的。

+0

這並沒有真正解決jtzero關於使用ref。 – Sean 2010-01-20 16:30:22

+1

byte []是System.Array的一個子類,它是一個引用類型。 – Will 2010-01-20 16:31:03

+0

@sean引用類型總是按引用傳遞,值類型總是按值傳遞...除非使用'ref'或'out',因此這些關鍵字存在的原因。將它們添加到參考參數中就像是一個未銳化的鉛筆。 – Will 2010-01-20 16:32:10

0

byte_array是一個引用類型。

1

C#是像Java在引用類型變量實際上是指針。您總是按值傳遞,但對於引用類型,值是對象的位置,而不是對象本身。引用類型的ref關鍵字通過引用傳遞指針,因此對ref參數的賦值將改變參數傳入的對象。

1

陣列中的.Net是引用類型。

因此,你的功能通過接收值到陣列對象的引用。由於仍然只有一個數組實例,因此該函數可以修改實例,並且可以看到調用者所做的更改。

添加ref關鍵字將使該函數接收對引用的數組對象的引用,並因此允許函數將引用更改爲引用不同的數組實例。

換句話說,在ref關鍵字將允許你寫:

public static void WriteInt(int i, ref byte[] byte_array, int pos) 
{ 
    byte_array = new byte[0]; //In the caller, the array will now be empty. 
} 

爲了證明:

void SetReference(ref byte[] arrayRef) { arrayRef = new byte[1]; } 

void SetValue(byte[] arrayVal) { arrayVal[1] = 42; } 

byte[] array = new byte[4]; 
byte[] sameArray = array; //sameArray refers to the same instance 

sameArray[0] = 77;   //Since it's the same instance, array[4] is also 77. 

SetValue(array);    //array[1] is 42. 
          //Since it refers to the same array, sameArray[1] is also 42. 

SetReference(ref array);  //sameArray now refers to a new array of length 1. 
          //array still refers to the original array. 
0

像尤里Faktorovich說,值類型(如int,焦炭,布爾ECC)。默認情況下,除非你指定裁判

所有其他類型(數組和對象通過了值()默認情況下,在你的榜樣通過了參考

如果u改變陣列內的值會反映變化,也該方法之外,但你不能重新分配的對象。

關於它的完整引用在MSDN

2

我認爲一些例子可以告訴你的參考和路過的價值引用類型和值類型之間和傳球之間的差異:

//Reference type 
class Foo { 
    public int I { get; set; } 
} 

//Value type 
struct Boo { 
    //I know, that mutable structures are evil, but it only an example 
    public int I { get; set; } 
} 


class Program 
{ 
    //Passing reference type by value 
    //We can change reference object (Foo::I can changed), 
    //but not reference itself (f must be the same reference 
    //to the same object) 
    static void ClassByValue1(Foo f) { 
     // 
     f.I++; 
    } 

    //Passing reference type by value 
    //Here I try to change reference itself, 
    //but it doesn't work! 
    static void ClassByValue2(Foo f) { 
     //But we can't change the reference itself 
     f = new Foo { I = f.I + 1 }; 
    } 

    //Passing reference typ by reference 
    //Here we can change Foo object 
    //and reference itself (f may reference to another object) 
    static void ClassByReference(ref Foo f) { 
     f = new Foo { I = -1 }; 
    } 

    //Passing value type by value 
    //We can't change Boo object 
    static void StructByValue(Boo b) { 
     b.I++; 
    } 

    //Passing value tye by reference 
    //We can change Boo object 
    static void StructByReference(ref Boo b) { 
     b.I++; 
    } 

    static void Main(string[] args) 
    { 
     Foo f = new Foo { I = 1 }; 

     //Reference object passed by value. 
     //We can change reference object itself, but we can't change reference 
     ClassByValue1(f); 
     Debug.Assert(f.I == 2); 

     ClassByValue2(f); 
     //"f" still referenced to the same object! 
     Debug.Assert(f.I == 2); 

     ClassByReference(ref f); 
     //Now "f" referenced to newly created object. 
     //Passing by references allow change referenced itself, 
     //not only referenced object 
     Debug.Assert(f.I == -1); 

     Boo b = new Boo { I = 1 }; 

     StructByValue(b); 
     //Value type passes by value "b" can't changed! 
     Debug.Assert(b.I == 1); 

     StructByReference(ref b); 
     //Value type passed by referenced. 
     //We can change value type object! 
     Debug.Assert(b.I == 2); 

     Console.ReadKey(); 
    } 

} 
2

考慮這一點的最好辦法就是想想變量 。變量按照定義存儲位置。您的程序中有哪些存儲位置?它們是:

  • 正式參數i和bufOutputStream的第一個WriteInt。
  • 第一個WriteInt中的本地變量緩衝區在它被分配之後由緩衝區引用的數組的元素(它們的「IntSize」)。
  • 形式參數I,BYTE_ARRAY和第二WriteInt

的BYTE_ARRAY存儲位置和緩衝存儲位置的POS是不同的存儲位置。但是byte_array存儲位置包含對緩衝區存儲位置引用的同一陣列的引用。因此,buffer [0]和byte_array [0]指向相同的存儲位置。

想想存儲位置,這一切都有意義。