关闭分配和通过引用传递

时间:2014-12-11 14:51:45

标签: c# closures

我的功能如下:

private void OnItemChannelsListChanged(object sender, ListChangedEventArgs args)
{
...
int index = args.NewIndex;
this.UpdateLogsOnNewAssignedUnit(ref index, channels);
}

,其中

private void UpdateLogsNewAssignedUnit(ref int index, List<IChannel> channels)
{
}

我使用了一个名为Heap Allocations Viewer插件的插件(ps。我不隶属于他们),它在编辑器上直观地显示堆分配。好吧,在它下面的ref int index参数中显示

  

关闭分配:'index','channels'参数和'this'参考

根据我的理解,传递int ref不应该创建新副本! 有谁知道它为什么会发生,我该怎么做才能避免呢?

非常感谢提前

1 个答案:

答案 0 :(得分:2)

从此

private void OnItemChannelsListChanged(object sender, ListChangedEventArgs args)

我认为你正在开一个活动,你没有像你在第一行所说的那样“有一个功能”。

如果从事件处理程序外部调用UpdateLogsNewAssignedUnit函数,我会打赌不会发生分配。事件通常实现为多播代理(它们不一定是,但通常是)。由于您是从事件处理程序调用它,因此编译器正在创建要在调用中使用的状态对象。有关详细信息,请参阅this文章。具体做法是:

  

在引入lambdas /匿名方法之前,想要调用接受委托的方法的C#开发人员通常需要定义一个类来存储它们的状态,向该类添加一个方法来进行处理,然后创建一个委托指向该状态实例上的该方法,例如

    public static void WriteOnPool(Stream stream, byte [] data) 
    { 
        var state = new WriteOnPoolState(); 
        state.stream = stream; 
        state.data = data; 
        ThreadPool.QueueUserWorkItem(new WaitCallback(state.Invoke)); 
    } 

    private sealed class WriteOnPoolState 
    { 
        public Stream stream; 
        public byte [] data; 

        public void Invoke(object ignored) 
        { 
            stream.Write(data, 0, data.Length); 
        }    
    }
  

现在在C#中,当您使用匿名方法或lambda时,编译器实际上最终会代表您生成几乎与此相同的代码,这样您就不必再手动执行此操作了。这是我之前使用匿名方法的示例生成的反编译版本:

    public static void WriteOnPool(Stream stream, byte[] data) 
    { 
        var locals2 = new DisplayClass1(); 
        locals2.stream = stream; 
        locals2.data = data; 
        ThreadPool.QueueUserWorkItem( 
            new WaitCallback(locals2.<WriteOnPool>b__0)); 
    } 

    [CompilerGenerated] 
    private sealed class DisplayClass1 
    { 
        public Stream stream; 
        public byte[] data; 

        public void <WriteOnPool>b__0(object param0) 
        { 
            this.stream.Write(this.data, 0, this.data.Length); 
        } 
    }