使用集合和参考关键字

时间:2016-03-01 13:01:52

标签: c# ref

我正在阅读有关ref关键字的MSDN页面,并使用集合而不是int修改了示例,如下所示:

public static void Main(string[] args)
{
    List<int> elements = new List<int>();
    Method(elements);               

    foreach(int val in elements)
    {
        Console.WriteLine(val);
    }
 }

static void Method(List<int> addelements)
{
        addelements.Add(1);
        addelements.Add(20);    
}

为什么没有ref关键字我可以看到在方法之外添加到集合中的int?当它只是int val时,我需要参考,看看方法做了哪些更改,但List<int>不是这样,为什么会这样?

更新

还有一个问题,我现在理解ref关键字和Lists。考虑到这一点,正在做以下多余的事情:

public static void Main(string[] args)
{
    List<int> elements = new List<int>();
    elements = Method(elements);                

    foreach(int val in elements)
    {
        Console.WriteLine(val);
    }
 }

static List<int> Method(List<int> addelements)
{
        addelements.Add(1);
        addelements.Add(20);
        return addelements;     
}

3 个答案:

答案 0 :(得分:0)

在c#中有两种对象引用类型和值类型。 (在不安全的情况下指针类型) 传递函数时:

1)Refs通过引用传递//不需要ref

2)值通过复制传递//你可以在这里使用ref来防止这种行为

static void Method(List<int> addelements)  // list is referance type

List是referance类型,它是整数的容器,所以如果容器是可变的,你可以改变它......

第二个问题: 取决于你在那种方法中做了什么......

1)如果您想稍后重用该方法,那将是个好主意

2)如果你在该列表上有大量的代码行,你可以使它更具描述性,将它们作为具有描述性名称的方法分开并按顺序调用它们而不是在一个方法体中进行...(排序)释放眼睛和大脑的压力:))

答案 1 :(得分:0)

在C#中有两种类型:引用和值类型(还有pointer type,但仅用于不安全的上下文)

值类型直接包含值,而引用类型包含对数据的引用。

Value Types

当传递值类型的变量作为参数时,该方法会接收原始对象的副本,以便在方法内进行的任何修改都不会持久。

值类型包含您自己定义的所有数字类型bool和枚举以及structs

(值的主要类型是结构和枚举,因为数值和bool实现为struct)。

  

请注意,您仍然可以pass a value type by reference by using the ref keyword.

Reference types

当将引用类型作为参数传递时,该方法接收引用的副本,因此该方法将使用相同的对象。所以在方法内进行的任何修改都将持续存在。

  

在C#中,string有一种特殊行为。它是通过引用传递并且是不可变的(它无法修改 - 如果修改string对象,新值将被复制到另一个对象中,旧的变量将引用新值。)

每个用户定义的类,接口和委托都通过引用传递。 此外,每个数组都通过引用传递。

因此,在您的情况下,您传递List<int>这是一个类的实例,因此它通过引用传递。

希望这能澄清一些事情。

祝你好运!

根据新问题更新

正如@fafase所说,你在做两件事:

  • 当您向列表中添加元素时(在方法中),您正在修改原始列表。
  • 当您返回相同的引用时,请执行以下操作:

elements = Method(elements); 您实际上将elements分配给从方法返回的列表(与您首先传递的相同,因为它是通过引用传递的)

简而言之,如果您只需要修改列表,只需使用void方法,就像原始问题一样。

答案 2 :(得分:0)

在C#中传递参数始终是值类型。

void Meth(int a){}
void Meth(object a){}

这两个方法接收值类型参数。有意义,因为第一个包含整数的值,第二个包含对象的地址的值。

如果更改值:

void Meth(int a){ a = 10; }
void Meth(object a){ object b = new object(); a = b;}

这两个影响参数的内容,但仅限于方法内。

void Example(){
    int a  = 0;
    Meth(a);
    print(a); // prints 0
}

这是因为使用了复制到参数的值而不是实际变量。

 void Meth(ref int a ){ a = 10;}
 void Example(){
    int a  = 0;
    Meth(ref a);
    print(a); // prints 10
 }

当您想要修改对象时,同样适用于对象。如果您在解除引用时修改成员,则不适用。

 void Meth(ObjectType o){
    o.dataMember = newValue;
 }

我们使用值0来查找该对象的存储位置并修改其成员。

这也是数组中发生的事情。传递给方法的值是存储整个集合的地址:

void Meth(int [] arr){  arr [0] = 20; }
void Example(){
   int [] a = new int[10];
   Meth(a);
   print(a[0]); // prints out 20
}

在此示例中,a是存储在内存中的10个数据的数组(0x00112233)。 arr参数被赋予该值,因此它是一个值类型变量,包含一个对象的地址(在我们的例子中是一个数组)。使用数组的索引有点像取消引用成员。所以它会影响数组的内容。

void Meth(int [] arr)
{
    arr = new int[5];
    arr[0] = 20;
}
void Example(){
   int [] a = new int[10];
   Meth(a);
   print(a[0]); // prints out 0
}

如果要修改整个数组,即创建一个新数组并将其分配给方法中的数组,则需要ref关键字。

void Meth( ref int [] arr)
{
    arr = new int[5];
    arr[0] = 20;
}
void Example(){
   int [] a = new int[10];
   Meth( ref a);
   print(a[0]); // prints out 20
}

这相当于将指针传递给C / C ++中的指针,因为该数组已经是指针,并且您正在向该指针传递指针。