您的位置:知识库 » .NET技术

警惕匿名方法造成的变量共享

作者: Jeffrey Zhao  来源: 博客园  发布时间: 2009-03-13 23:29  阅读: 2055 次  推荐: 0   原文链接   [收藏]  

解决问题

  找到了问题所在,解决起来自然轻而易举:

private class WrapperClass
{
    private List<Item> m_items;

    public WrapperClass(List<Item> items)
    {
        this.m_items = items;
    }

    public void WaitCallback(object o)
    {
        DataContext db = new DataContext();
        db.Items.InsertAllOnSubmit(this.m_items);
        db.SubmitChanges();
    }
}

static void Process()
{
    List<Item> batchItems = new List<Item>();
    foreach (var item in ...)
    {
        batchItems.Add(item);

        if (batchItems.Count > 1000)
        {
            ThreadPool.QueueUserWorkItem(
                new WrapperClass(batchItems).WaitCallback);

            batchItems = new List<Item>();
        }
    }
}

  这里我们明确地准备一个封装类,用它来保留我们需要提交的数据。而每次提交时则使用保留好的数据,自然不会发生不该有的“数据共享”,从而避免了错误的发生1

总结

  匿名方法是强大的,但是也会造成一些令人难以察觉的陷阱。对于使用匿名方法创建的委托,如果不会立即同步执行,并且其中使用了方法的局部变量,那么您就需要对其留个心眼了。因为此时“局部变量”事实上已经由编译器转变成一个自动类的实例上的Field字段,而这个字段将被当前方法和委托对象共享。如果您在创建了委托对象之后还会修改共享的“局部变量”,那么请再三确认这样做符合您的意图,而不会造成问题。

  此类问题也不光会出现在匿名方法中。如果您使用Lambda表达式创建了一个表达式树,其中也用到了一个“局部变量”,那么表达式树在解析或执行时同样也会获取“当前”的值,而不是创建表达式树时的值。

  这也是为什么Java中的内联写法——匿名类——如果要共享方法内的“局部变量”,则必须将变量使用final关键字来修饰:这样这个变量只能在声明时赋值,避免了后续的“修改”可能会造成的“古怪问题”。

 

注1:一个更简洁的解决方案可以参考29楼overred兄弟的回复。

 

0
0

.NET技术热门文章

    .NET技术最新文章

      最新新闻

        热门新闻