代码改变世界

访问匿名方法块“外部”变量的需要注意的问题

2009-06-20 20:49 by 晓风残月, ... 阅读, ... 评论, 收藏, 编辑

通常情况,下面的匿名方法执行没有问题

    // Declare a delegate
    delegate void Callback(int arg);

    class TestClass
    {
        public static void Main()
        {
            int n = 10;   
            Callback c = (m) => {
                System.Console.WriteLine("匿名方法块“外部”变量 n is " + n);
                System.Console.WriteLine("匿名方法参数 m is " + m); 
            };
            c(11);
        }        
    }

 

下面的 ASP.NET 代码应该也没有什么问题

    protected override void OnInit(EventArgs e)
    {     
        //   
        HttpContext ctx = HttpContext.Current;
        Button1.Click += (sender, args) =>
        {            
            ctx.Response.Write("Server Time: " + DateTime.Now);
        };        
        //        
        base.OnInit(e);
    }

但是,下面的代码呢?

    public class ErrorHandlerModule : IHttpModule
    {

        #region IHttpModule Members

        public void Dispose()
        {

        }

        public void Init(HttpApplication app)
        {
            HttpContext ctx = app.Context;         
            app.Error += (sender, e)
            {
                ctx.Response.Clear();
                ctx.Response.Write(String.Format("<pre>ErrorHandlerModule:\n{0}</pre>", ctx.Error.ToString()));
                ctx.ClearError();
                ctx.Response.End();
            };
        }      

        #endregion
    }

加载上面这个 HttpModule,错误处理并不会按预期的输出错误,我的测试的结果是:假如的第一个请求刚好发生了异常,那么会输出这个异常;接下来所有的请求即使有错误也不会输出了。

稍微修改下,就能得到正确的结果了:

public void Init(HttpApplication app)
        {
           //HttpContext ctx = app.Context;  // or HttpContext.Current       
            app.Error += (sender, e)
            {
                HttpContext ctx = HttpContext.Current;         
中超-北京平河南无缘5连胜 天津平青岛                ctx.Response.Clear();
                ctx.Response.Write(String.Format("<pre>ErrorHandlerModule:\n{0}</pre>", ctx.Error.ToString()));
                ctx.ClearError();
                ctx.Response.End();
            };
        }    
注意到, HttpContext 是一个请求一个实例,IHttpModule.Init 只在应用程序启动(第一个请求到来)时执行一次,因此第一种情况中后续的请求即使再发生错误 ctx 也指向是第一次请求的
HttpContext 实例,并且这个实例不会被释放。因此,匿名方法访问外部变量一定要注意这个变量是否每次执行这个片段语义上是否一致。