2010-01-20 42 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]指向相同的存储位置。

想想存储位置,这一切都有意义。