我不是套接字编程的老手,所以在分析我在数据库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);
}
我理解我不理解的位移是'缓冲'var在args中没有 ref 或者没有返回时如何保持值。位移是以某种方式编辑缓冲区的实际值?
答案 0 :(得分:20)
你的困惑很常见。关键点在于意识到“引用类型”和“通过引用”(ref
键盘)完全独立。在这种特定情况下,由于byte[]
是引用类型(与所有数组一样),这意味着在传递对象时不会复制该对象,因此您总是引用同一个对象。
我强烈建议你阅读Jon Skeet关于Parameter passing in C#的优秀文章,一切都应该清楚......
答案 1 :(得分:5)
因为数组不是值类型,所以它是引用类型。对堆上位置的引用按值传递。
答案 2 :(得分: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();
}
}
答案 3 :(得分:2)
考虑这个问题的最佳方法是考虑变量。根据定义,变量是存储位置。您的计划中有哪些存储位置?他们是:
byte_array存储位置和缓冲区存储位置是不同的存储位置。但是byte_array存储位置包含对缓冲区存储位置所引用的同一数组的引用。因此,buffer [0]和byte_array [0]指的是相同的存储位置。
想想存储位置,这一切都有意义。
答案 4 :(得分:1)
C#就像Java一样,引用类型变量实际上是指针。您始终按值传递,但使用引用类型时,值是对象的位置,而不是对象本身。引用类型上的ref关键字通过引用传递指针,因此对ref参数的赋值将更改传递的参数指向的对象。
答案 5 :(得分: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.
答案 6 :(得分:0)
byte_array是一种引用类型。
答案 7 :(得分:0)
就像Yuriy Faktorovich所说的那样,值默认值传递值类型(如int,char,bool ecc。)(除非指定 ref )
默认情况下,所有其他类型(数组和对象)都通过引用传递
在您的示例中,如果您更改数组中的值,它将反映方法之外的更改,但您无法重新分配该对象。
有关它的完整参考位于MSDN