【问题标题】:Confusing behavior of extension method with new object creation in method扩展方法的行为与方法中的新对象创建混淆
【发布时间】:2012-04-13 05:32:22
【问题描述】:

我试图了解 c# 的扩展方法的行为,发现以下内容:

下面是类 Program 的扩展方法,它有一个名为 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 = new Program() 到底发生了什么?

【问题讨论】:

  • 您在发布此问题之前是否尝试过调试器流程
  • 调试的代码不多..
  • 那我假设你不知道消息传递

标签: c# extension-methods


【解决方案1】:

基本上,它的行为完全与没有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();

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

p.SeeIt = 100;

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

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

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

      不幸的是,您不能执行使用 ref 这个参数的扩展方法。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-23
        • 1970-01-01
        • 2011-09-25
        • 1970-01-01
        • 2019-04-06
        相关资源
        最近更新 更多