将扩展方法的行为与方法中的新对象创建混淆

本文关键字:方法 对象 创建 扩展 新对象 | 更新日期: 2023-09-27 18:31:03

我试图理解 c# 扩展方法的行为,发现如下:

下面是类程序的扩展方法,其中有一个名为 SeeIt 的字段。

public static void Prod(this Program p)
{
   Console.WriteLine("i am in ext- pro" );
   p = new Program();   // look out for this line (call this line as #@2)
   p.SeeIt = 100;
}

现在当我像这样调用此方法时:

var pr = new Program();
pr.SeeIt = 200;
pr.Prod();
COnsole.WriteLine(pr.SeeIt);

我看到下面的东西:

  1. 当我在扩展方法中评论#@2行时,结果来自扩展方法,即100。
  2. 当我保持行 #@2 行时,结果是 200。

我想知道:

  • 我说 p = 扩展方法中的新程序()到底发生了什么?

将扩展方法的行为与方法中的新对象创建混淆

基本上,它的行为与没有this的行为完全相同。扩展方法只会使 API 方便 - 它们不会改变行为。

参数 p 不会传递ref,因此一旦您这样做p = new Program();您就创建了一个单独的且不相关的实例,该实例将无法返回到调用代码中。因此,调用方将看不到您的更改,并且100仅在Prod中可见。

或者更具体地说:

pr.Prod();

与 相同

DeclaringType.Prod(pr);

它将pr的值(引用)加载到堆栈上,并通过静态调用调用Prod;

public static void Prod(this Program p)

此时,p位于位置 arg0 的堆栈上。

p = new Program();

创建一个新对象并在arg0分配值 - 请注意,pr(引用)的值不受此影响,因为arg0是引用的单独内存位置。

p.SeeIt = 100;

通过取消引用arg0将成员分配给对象新对象 - 同样,pr末尾的对象对此一无所知。

它正在创建Program的新实例,并且您正在更新该实例的 SeeIt 属性。

a) 当 #@2 被注释时,您正在更新程序原始实例的值,因此设置了属性 100

b) 创建新实例时,旧实例不受影响,属性值不受影响

您正在将 p 的引用替换为另一个实例,这不会影响您传递给扩展方法的引用。我认为您要做的是使参数 p 成为 ref 参数,在这种情况下,传递给方法的内容与方法本身中使用的引用将是相同的。

不幸的是,您无法执行采用 ref 此参数的扩展方法。

请记住,引用基本上是指向实际类实例的指针。