8

我不是套接字编程的老手,所以在分析我在数据库 API 中找到的代码时,我遇到了这段代码

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

我理解位移我不理解的是,当 args 中没有ref或没有返回时,'buffer' var 如何不断获取值。位移以某种方式编辑缓冲区的实际值?

4

8 回答 8

24

你的困惑是很常见的。关键是要意识到“引用类型”和“通过引用”(ref键盘)是完全独立的。在这种特定情况下,由于byte[]是引用类型(所有数组也是如此),这意味着当您传递对象时不会复制对象,因此您总是引用同一个对象。

我强烈建议您阅读 Jon Skeet 关于C# 参数传递的优秀文章,一切都应该变得清晰......

于 2010-01-20T16:36:09.813 回答
6

因为数组不是值类型,所以它是引用类型。对堆上位置的引用是按值传递的。

于 2010-01-20T16:24:18.077 回答
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();
    }

}
于 2010-01-20T17:17:31.103 回答
2

考虑这一点的最好方法是考虑变量。根据定义,变量是存储位置。您的程序中的存储位置是什么?他们是:

  • 第一个WriteInt 的形参i 和bufOutputStream。
  • 第一个 WriteInt 中的局部变量缓冲区
  • 分配缓冲区后,缓冲区引用的数组的元素(其中的“IntSize”)。
  • 第二个 WriteInt 的形参 i、byte_array 和 pos

byte_array 存储位置和缓冲区存储位置是不同的存储位置。但是 byte_array 存储位置包含对缓冲区存储位置所引用的同一数组的引用。因此 buffer[0] 和 byte_array[0] 指的是同一个存储位置。

想想存储位置,一切都会说得通。

于 2010-01-20T19:34:15.427 回答
1

C# 与 Java 类似,引用类型变量实际上是指针。您总是按值传递,但对于引用类型,值是对象的位置,而不是对象本身。引用类型上的 ref 关键字通过引用传递指针,因此对 ref 参数的赋值将改变传入的参数指向的对象。

于 2010-01-20T16:29:47.487 回答
1

.Net 中的数组是引用类型。

因此,您的函数按值接收对数组对象的引用。由于仍然只有一个数组实例,因此该函数可以修改实例,并且调用者将看到更改。

添加ref关键字将使函数通过 reference 接收对数组对象的引用,因此允许函数更改引用以引用不同的数组实例。

换句话说,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.
于 2010-01-20T16:30:38.230 回答
0

byte_array 是一个引用类型。

于 2010-01-20T16:26:57.367 回答
0

就像 Yuriy Faktorovich 所说,值类型(如 int、char、bool ecc。)默认按值传递(除非您指定ref

所有其他类型(数组和对象)默认通过引用传递

在您的示例中,如果您更改数组内的值,它将反映方法外的更改,但您不能重新分配对象。

关于它的完整参考在MSDN

于 2010-01-20T16:32:18.087 回答