匿名委托关闭(或者为什么这有效)?

发布于 2024-09-24 05:46:06 字数 444 浏览 1 评论 0原文

下面的代码直接取自 MSDN 介绍 MVVM 设计的文章附带的示例项目模式。我不太明白为什么委托会看到“handler”的值而不是 null。我的理解是,为委托方法创建的闭包包含范围内到目前为止在执行中已初始化的所有变量,并且由于在创建委托后重新分配“处理程序”,闭包将包含设置为 null 的“处理程序” 。

康斯坦丁


EventHandler handler = null;
handler = delegate
{
    viewModel.RequestClose -= handler;
    window.Close();
};
viewModel.RequestClose += handler;

The code below is taken directly from the sample project accompanying the article on MSDN introducing MVVM design pattern. I do not quite understand why the delegate sees the value of 'handler' other than null. My understanding was that the closure created for the delegate method contains all variables in scope that have been initialized up to this point in the execution, and since 'handler' is reassigned after the delegate is created the closure will contain 'handler' set to null.

Konstantin


EventHandler handler = null;
handler = delegate
{
    viewModel.RequestClose -= handler;
    window.Close();
};
viewModel.RequestClose += handler;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

ま柒月 2024-10-01 05:46:06

委托捕获变量handler,而不是变量的内容。


当您查看 C# 编译器将代码编译为什么(例如使用 Reflector)时,情况会变得更加清楚。您的代码大致编译为:

class MyAnonymousDelegate
{
    public ... viewModel;
    public ... window;
    public EventHandler handler;

    public void DoIt(object sender, EventArgs e)
    {
        this.viewModel.RequestClose -= this.handler;
        this.window.Close();
    }
}

var mad = new MyAnonymousDelegate();
mad.viewModel = viewModel;
mad.window = window;
mad.handler = null;

mad.handler = new EventHandler(mad.DoIt);

viewModel.RequestClose += mad.handler;

The delegate captures the variable handler, not the contents of the variable.


It becomes more clear when you look at what the C# compiler compiles your code to, e.g., using Reflector. Your code is compiled roughly to this:

class MyAnonymousDelegate
{
    public ... viewModel;
    public ... window;
    public EventHandler handler;

    public void DoIt(object sender, EventArgs e)
    {
        this.viewModel.RequestClose -= this.handler;
        this.window.Close();
    }
}

var mad = new MyAnonymousDelegate();
mad.viewModel = viewModel;
mad.window = window;
mad.handler = null;

mad.handler = new EventHandler(mad.DoIt);

viewModel.RequestClose += mad.handler;
野心澎湃 2024-10-01 05:46:06

像这样写:

EventHandler handler = delegate
{
    viewModel.RequestClose -= handler;
    window.Close();
};
viewModel.RequestClose += handler;

要得到错误CS0165:使用未分配的局部变量“处理程序”。

有问题的诊断,它实际上并不是未分配的。事实上,实现匿名方法的隐藏类是在分配捕获的“handler”值之前创建的。不过,这在 C# 编译器中实现起来并不容易。边缘情况。

Write it like this:

EventHandler handler = delegate
{
    viewModel.RequestClose -= handler;
    window.Close();
};
viewModel.RequestClose += handler;

To get error CS0165: Use of unassigned local variable 'handler'.

Questionable diagnostic, it isn't actually unassigned. The hidden class that implements the anonymous method does in fact get created before the captured value of 'handler' is assigned. That cannot be easy to implement in the C# compiler though. Edge case.

陪我终i 2024-10-01 05:46:06

闭包不复制变量,它维护一个引用。当创建委托并设置处理程序时,此更改将被更新。

A closure doesn't copy the variables, it maintains a reference. When the delegate is created and the handler is set, this change is updated.

今天小雨转甜 2024-10-01 05:46:06

处理程序在分配之前初始化:

       static void Main(string[] args)
    {

        EventHandler handler = null;

        handler = delegate
        {
            AppDomain.CurrentDomain.ProcessExit -= handler;

        };
        AppDomain.CurrentDomain.ProcessExit += handler;
    }

编译为:

.method private hidebysig static void  Main(string[] args) cil managed
{
   .entrypoint
   // Code size       51 (0x33)
   .maxstack  4
   .locals init ([0] class ConsoleApplication1.Program/'c__DisplayClass1'    'CS$8__locals2')
   IL_0000:  newobj     instance void    ConsoleApplication1.Program/'c__DisplayClass1'::.ctor()
   IL_0005:  stloc.0
  IL_0006:  nop
  IL_0007:  ldloc.0
  IL_0008:  ldnull
  IL_0009:  stfld      class [mscorlib]System.EventHandler ConsoleApplication1.Program/'c__DisplayClass1'::'handler'
  IL_000e:  ldloc.0
  IL_000f:  ldloc.0
  IL_0010:  ldftn      instance void ConsoleApplication1.Program/'c__DisplayClass1'::'b__0'(object,
                                                                                                    class [mscorlib]System.EventArgs)
  IL_0016:  newobj     instance void [mscorlib]System.EventHandler::.ctor(object,
                                                                          native int)
  IL_001b:  stfld      class [mscorlib]System.EventHandler ConsoleApplication1.Program/'c__DisplayClass1'::'handler'
  IL_0020:  call       class [mscorlib]System.AppDomain [mscorlib]System.AppDomain::get_CurrentDomain()
  IL_0025:  ldloc.0
  IL_0026:  ldfld      class [mscorlib]System.EventHandler ConsoleApplication1.Program/'c__DisplayClass1'::'handler'
  IL_002b:  callvirt   instance void [mscorlib]System.AppDomain::add_ProcessExit(class [mscorlib]System.EventHandler)
  IL_0030:  nop
  IL_0031:  nop
  IL_0032:  ret
} // end of method Program::Main

The handler is initialised before asigning:

       static void Main(string[] args)
    {

        EventHandler handler = null;

        handler = delegate
        {
            AppDomain.CurrentDomain.ProcessExit -= handler;

        };
        AppDomain.CurrentDomain.ProcessExit += handler;
    }

Compiles to:

.method private hidebysig static void  Main(string[] args) cil managed
{
   .entrypoint
   // Code size       51 (0x33)
   .maxstack  4
   .locals init ([0] class ConsoleApplication1.Program/'c__DisplayClass1'    'CS$8__locals2')
   IL_0000:  newobj     instance void    ConsoleApplication1.Program/'c__DisplayClass1'::.ctor()
   IL_0005:  stloc.0
  IL_0006:  nop
  IL_0007:  ldloc.0
  IL_0008:  ldnull
  IL_0009:  stfld      class [mscorlib]System.EventHandler ConsoleApplication1.Program/'c__DisplayClass1'::'handler'
  IL_000e:  ldloc.0
  IL_000f:  ldloc.0
  IL_0010:  ldftn      instance void ConsoleApplication1.Program/'c__DisplayClass1'::'b__0'(object,
                                                                                                    class [mscorlib]System.EventArgs)
  IL_0016:  newobj     instance void [mscorlib]System.EventHandler::.ctor(object,
                                                                          native int)
  IL_001b:  stfld      class [mscorlib]System.EventHandler ConsoleApplication1.Program/'c__DisplayClass1'::'handler'
  IL_0020:  call       class [mscorlib]System.AppDomain [mscorlib]System.AppDomain::get_CurrentDomain()
  IL_0025:  ldloc.0
  IL_0026:  ldfld      class [mscorlib]System.EventHandler ConsoleApplication1.Program/'c__DisplayClass1'::'handler'
  IL_002b:  callvirt   instance void [mscorlib]System.AppDomain::add_ProcessExit(class [mscorlib]System.EventHandler)
  IL_0030:  nop
  IL_0031:  nop
  IL_0032:  ret
} // end of method Program::Main
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文