【问题标题】:Why is it possible to access a constructor parameter after it becomes out of scope? [duplicate]为什么在超出范围后可以访问构造函数参数? [复制]
【发布时间】:2018-06-03 07:29:52
【问题描述】:

为什么可以在下面的示例中调用 SomeMethod() 方法?

我认为构造函数参数 loggerFactoryLogger 属性尝试访问它时将不再可用。

我在设置 lazyLogger 字段时使用了一个函数,但我认为当我调用 Logger 属性时它会抛出某种异常。

但一切正常。 这可能只是我对 CLR/C# 工作原理的误解。

我希望能解释一下它为什么会这样工作。

public class TestClass
{
  private readonly Lazy<ILogger> lazyLogger;

  private ILogger Logger => this.lazyLogger.Value;

  public TestClass(ILoggerFactory loggerFactory)
  {
    this.lazyLogger = new Lazy<ILogger>(() = > loggerFactory.GetLogger("TestLogger"));
  }

  public void SomeMethod()
  {
    this.Logger.Info("Test Log Message"); //Why is it okay to call this method?  The constructor parameter shouldn't be available anymore, right?
  } 
}

public interface ILoggerFactory
{
  ILogger GetLogger(string name);
}

public interface ILogger
{
  void Info(string message);
}

public class TestLoggerFactory : ILoggerFactory
{
  public ILogger GetLogger(string name)
  {
      return new TestLogger(name);
  }
}

public class TestLogger : ILogger
{
  public void Info(string message)
  {
    Console.WriteLine(message);
  }
}

【问题讨论】:

  • 在传递给 Lazy&lt;ILogger&gt; 构造函数的委托中,您正在关闭 loggerFactory
  • 嘿,如果我把我的贵重物品放在一个盒子里然后把那个盒子给别人,他是怎么拿到我的贵重物品的?我从来没有给过他,我只给了他一个盒子!
  • @Lee,当你说我结束时,你是什么意思?

标签: c# .net clr


【解决方案1】:

由于您在 lambda 中访问此参数

() = > loggerFactory.GetLogger("TestLogger");

编译器会创建一些额外的代码来捕获该变量。它看起来像这样:

public class TestClass
{
    /* your fields here */

    // created by compiler
    private ILoggerFactory anonymousField; 
    private ILogger AnonymousMethod()
    {
         return anonymousField.GetLogger("TestLogger");
    }

    public TestClass(ILoggerFactory loggerFactory)
    {
        // save field
        this.anonymousField = loggerFactory;
        // use instance method instead with captures anonymousField
        this.lazyLogger = new Lazy<ILogger>(AnonymousMethod); 
    }

正如 cmets 中提到的,实际上生成了一个全新的类,它声明了该匿名方法并将所有必要的变量作为字段。但这是基本思想。

【讨论】:

  • 关闭方面对我来说是新的。没有这方面的知识可能是我的错。
  • 实际上编译器为 lambda 创建了一个新的委托类,其中包含捕获变量的字段。
  • @IssaFram 抱歉,我的英语有时缺少正确的编译器魔法措辞。虽然对于正常的对话来说已经足够了,但我永远不明白为什么它被称为/“关闭”/“捕获”等的确切含义是什么。在这种情况下。
  • @OlivierJacot-Descombes 对此不确定,不久前我检查了反编译的 IL,我想我记得它尽可能将值保持在同一个类中。不确定这是否是一个实现细节。
  • 请参阅:stackoverflow.com/a/742474/880990 和更深入的信息:The Beauty of Closures C#。两者都由乔恩·斯基特(Jon Skeet)撰写。
猜你喜欢
  • 1970-01-01
  • 2011-05-06
  • 1970-01-01
  • 1970-01-01
  • 2018-01-29
  • 2014-08-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多