Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/328.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Foreach循环将迭代变量传递给一个有ref和没有ref的方法-不明白为什么它不允许有ref_C#_Foreach - Fatal编程技术网

C# Foreach循环将迭代变量传递给一个有ref和没有ref的方法-不明白为什么它不允许有ref

C# Foreach循环将迭代变量传递给一个有ref和没有ref的方法-不明白为什么它不允许有ref,c#,foreach,C#,Foreach,今天早上,我一直在努力理解以下内容,我希望有人能很好地解释为什么这样做行不通。我在LinqPad上做了一个例子,复制了我的问题: void Main() { var myPeople = new People(); myPeople.MyPeople.Add(new Person { Name = "Joe", Surname = "Doe" }); foreach (var person in myPeople.MyPeople) { //this is inte

今天早上,我一直在努力理解以下内容,我希望有人能很好地解释为什么这样做行不通。我在
LinqPad
上做了一个例子,复制了我的问题:

void Main()
{
  var myPeople = new People();
  myPeople.MyPeople.Add(new Person { Name = "Joe", Surname = "Doe" });

  foreach (var person in myPeople.MyPeople)
  {
      //this is intermediate variable is still a reference to the iteration variable
       var intermediate = person;
       myPeople.ChangeName(ref intermediate);

      //both names were changed, so why cant i just pass in 'person' directly since its still changing it.

      intermediate.Name.Dump();
      person.Name.Dump();
  }

}

 public class People
 {
     public People()
     {
        MyPeople = new List<Person>();
     }

    public List<Person> MyPeople { get; set; }

    public void ChangeName(ref Person person)
    {
       person.Name = "Changed";
    }
}

public class Person
{
   public string Name { get; set; }

   public string Surname { get; set; }
}
void Main()
{
var myPeople=新人();
myPeople.myPeople.Add(newperson{Name=“Joe”,姓氏=“Doe”});
foreach(myPeople.myPeople中的var person)
{
//这是中间变量,仍然是迭代变量的引用
var中间值=人;
myPeople.ChangeName(ref intermediate);
//两个名字都变了,既然“person”还在变,为什么我不能直接输入它呢。
intermediate.Name.Dump();
person.Name.Dump();
}
}
公营阶层人士
{
公众人士()
{
MyPeople=新列表();
}
公共列表MyPeople{get;set;}
公共无效变更名称(参考人)
{
person.Name=“已更改”;
}
}
公共阶层人士
{
公共字符串名称{get;set;}
公共字符串姓氏{get;set;}
}
因此,解释了
foreach
变量是只读变量,这就是为什么不能用另一个变量替换它-这很有意义,但是如果我用
ref
将它传递到上面的
ChangeName
方法中,编译器将不允许它。但是,如果我删除
ChangeName
方法上的
ref
,它将允许我传入foreach变量,但从技术上讲,它仍然是
reference
,而不明确指出它是
ref
对吗

那么为什么会发生这种情况呢?此外,如果我把它赋给上面的一个中间变量,那么它将允许我以
ref
的形式传递它,即使它仍然是对原始变量的引用,所以技术上指向相同的内存位置,这意味着相同的对象,对吗

所以我的问题是为什么C#编译器不让我将迭代变量传递给一个带有
ref

Rafalon对问题的进一步澄清: 当
person
变量指向与
intermediate
变量相同的对象时,为什么编译器不允许myPeople.ChangeName(ref person),但允许myPeople.ChangeName(ref intermediate)?

最后解释了所有这一切;常规
foreach
的l值被视为“只读”-您不能:

person=newperson();
比如说。
ref
用法要求参数not是只读的,否则我们就违反了减少只读的承诺,因为该方法可能会修改原本是只读的内容。在这种情况下,由于
Person
是一个类,因此它只与实际引用本身相关,而与底层对象无关

不过,有一个好消息:我们现在在中有了
,这类似于
ref
,但是对于只读场景,所以:将
public void ChangeName(ref Person)
更改为
public void ChangeName(Person)
,它应该可以工作:

myPeople.ChangeName(亲自);
对此的限制是,在
ChangeName
方法中,您不能执行以下操作:

public void ChangeName(亲自)
{
person=新的person();//无效
}
强调:在
中的
用法实际上并不适用于类;它用于
struct
,尤其是
readonly struct
——以避免复杂和大值类型的防御堆栈副本

在C#的最新版本中,还有一个
ref readonly
概念,根据该概念,l值是ref
Foo
(适用于任何类型的
Foo
)。这需要一个带有
public-ref-Foo-Current{get;}
访问器的自定义迭代器,而不是
public-Foo-Current{get;}
访问器,即它显式绑定到ref-return。当l值为ref时,可以在采用
ref
的方法中使用它



重要的是,尽管我知道OP知道这一点:在这个场景中,您不需要
ref
,因为
Person
本身就是一个类;代码在没有ref的情况下运行正常,对象将正确更新。

当您传递ref intermediate时,您将引用传递给变量intermediate,而不是它所指向的对象。如果将一个新的Person分配给ChangeName中的Person变量,中间变量将被更改


这就是为什么不允许在foreach中传递ref person,因为您可以更改foreach变量的值。

“但从技术上讲,它仍然是一个引用”-这里的区别是“一个引用”与“一个引用的引用”;但更让人困惑的是,c#“latest”支持
ref foreach
,其中l值是一个引用(即在这种情况下是
ref Person
),在这种情况下它会工作!注意:大多数人永远不需要知道或关心
ref-foreach
:)假设我们将
public-void-ChangeName(ref-Person-Person){Person=null;}
。所需的
forloop
行为是什么?在
intermediate
的情况下,它是
intermediate==null
,而循环变量(
person
)没有更改。因此问题是“为什么编译器不允许
myPeople.ChangeName(ref-person)
但允许
myPeople.ChangeName(ref-intermediate)
person=intermediate
时,”,对吗?
//这是中间变量,它仍然是对迭代变量的引用
不,它不是。它是对
迭代
引用的同一对象的引用。这种区别可能看起来很微妙,但很重要。请重新阅读MSDN中关于ref和out关键字的内容。我不明白你所说的“两者都会改变”是什么意思,你能更具体一点吗?你可以通过chang含蓄地传递对两者的引用