IConfiguration.Bind() 如何在没有 'out' 或 'ref' 参数的情况下在 .NET Core 中工作?

How IConfiguration.Bind() Works In .NET Core without 'out' or 'ref' in it's Arguments?

在 .NET Core 中,我们使用 IConfiguration 将配置绑定到实例。

var settings = new AppSettings();
Configuration.GetSection("AppSettings").Bind(settings);

为了在我的个人项目中创建类似 Bind() 的函数(针对不同的要求),我创建了一个这样的方法

public void BindOption(ref object instance)
{
  ...
}

然后像这样使用它

var settings = new AppSettings();
MyCustomStaticClass.BindOption(ref settings);

现在我的问题是

Bind() 函数如何在其参数中未明确提及 outref 的情况下工作?

听起来你误解了 ref/out - 当你使用引用类型 (class) 传递给方法,允许方法将对象的新实例分配给参数变量,并且调用代码可以看到更改。绝对不需要更改传递变量的某些数据内容。

我个人认为围绕这​​个的很多混淆来自短语“通过引用传递”,其中有一个以 ref 开头的词,巧合的是 ref[ 中的 3 个字母=35=]

创建引用类型实例时:

Person john = new Person(){ Name = "John", Age = 27 };

您可以将其传递给方法:

void ChangeName(Person p){
  p.Name = "Fred";
}

您无需指定 ref 即可更改并保留此名称

ChangeName(john);
Console.Print(john.Name); //Fred

在 C# 内部,假设您创建 John 并且 C# 分配一些内存,将名称放入其中并为您提供变量引用:

john --> { Name: "John", Age: 27 }

您调用该方法,C# 临时 生成另一个引用 p(因为该方法采用 Person p)

john --> { Name: "John", Age: 27 } <-- p

新引用,相同对象。您通过 p.Name 更改名称,原始对象受到影响

john --> { Name: "Fred", Age: 27 } <-- p

如果我们使用 ref C# 没有创建新的引用,假设它只是暂时重命名我们现有的引用,然后在方法完成后将其重新命名

void ChangeName(ref Person p){
  p.Name = "Fred";
}


john --> { Name: "John", Age: 27 }      //start with
p --> { Name: "John", Age: 27 }          //when start calling the method 
p --> { Name: "Fred", Age: 27 }          //method changes the person name
john --> { Name: "Fred", Age: 27 }      //method exits, name is changed

我们这里从来不需要参考


不同的场景。人是不变的。更改名称的唯一方法是将其换成一个全新的对象

void ChangeName(Person p){
  p = new Person { Name = "Fred", Age: 0 };
}

现在,这个需要参考。看看当我们没有 ref:

时会发生什么
john --> { Name: "John", Age: 27 }
john --> { Name: "John", Age: 27 } <-- p
john --> { Name: "John", Age: 27 }     p --> { Name: "Fred", Age: 0 }
john --> { Name: "John", Age: 27 }

调用该方法对旧对象进行新引用,然后说 p = new... 将新引用重新附加到某个新对象,该对象在方法结束时立即销毁,没有任何改变

参考:

john --> { Name: "John", Age: 27 }
p --> { Name: "John", Age: 27 } 
p --> { Name: "Fred", Age 0 }
john --> { Name: "Fred", Age 0 }

临时重命名该引用意味着当我们创建一个新对象并分配它时,原始调用代码也会遇到 new


仅当您将传入的内容设置为 new 并希望调用者看到新内容时才需要 ref。大多数时候我们不需要它

脚注:outref 类似,只是编译器会检查该方法是否确实赋值。在将变量传递给方法时,您需要使用“out”或“ref”,因为它会引起您的注意“此方法可能会覆盖您传入的任何内容”(对于 ref)或“此方法肯定会覆盖您输入的任何内容”通过”(带出)

现代 .net 也有很少使用的 in 修饰符,它使编译器检查你没有为传入变量分配 new 任何东西(运行 方法结束时 Fred 丢失的非 ref 场景的风险)