为什么要进行垃圾收集,关闭和Lambda禁用棱镜事件聚合器预订?

时间:2019-03-07 10:51:07

标签: c# lambda garbage-collection closures eventaggregator

我有一个使用PRISM事件聚合器模式定义的简单事件

 public class TestEvent : PubSubEvent
    {
    }
    public static class PrismEvents
    {
        public static readonly IEventAggregator EventAggregator = new EventAggregator();
        public static readonly TestEvent EventTest = EventAggregator.GetEvent<TestEvent>();
    }

我有一个订户类,该事件使用lambda进行订阅。请注意,在订阅代码中使用局部变量(i)

public class SubScriber
    {
        public SubScriber()
        {
            int i = 5;
            PrismEvents.EventTest.Subscribe(() =>
            {
                Console.WriteLine("Event Fired");//not getting called
                i = 10; //commenting this line will execute the subscription code
            });
        }

    }

在发布者侧创建订户,然后调用GC,然后发布事件。

订阅代码未执行!

 class Program
    {
        static void Main(string[] args)
        {
            new SubScriber();
            GC.Collect(); //commenting this line will execute the subscription code
            PrismEvents.EventTest.Publish();
            Console.ReadKey();
        }

    }

点对

  1. 注释局部变量(i = 10)的使用将修复 问题。订阅代码将按预期执行

  2. 评论GC.collect将解决此问题。订阅代码将     按预期执行

此行为的原因是什么?

1 个答案:

答案 0 :(得分:0)

好问题。 我没有所有答案,但是Prism使用WeakReference。 订阅可在参数中使用的委托(动作)上创建WeakReference。 确切地说,WeakReference是在委托的Target上进行的。 这里有一些代码可以更好地理解发生了什么:

public class SubScriber
    {
        [CompilerGenerated]
        private sealed class <>c__DisplayClass0_0
        {
            public int i;

            internal void ctor>b__0()
            {
                Console.WriteLine("Event Fired action1");
                this.i = 11;
            }
        }

        [CompilerGenerated]
        [Serializable]
        private sealed class <>c
        {
            public static readonly Program.SubScriber.<>c <>9 = new Program.SubScriber.<>c();

            public static Action <>9__0_1;

            internal void ctor>b__0_1()
            {
                Console.WriteLine("Event Fired action2");
            }
        }

        public SubScriber()
        {
            Program.SubScriber.<>c__DisplayClass0_0 <>c__DisplayClass0_ = new Program.SubScriber.<>c__DisplayClass0_0();
            <>c__DisplayClass0_.i = 5;
            Action action = new Action(<>c__DisplayClass0_.<.ctor>b__0);
            Action arg_41_0;
            if ((arg_41_0 = Program.SubScriber.<>c.<>9__0_1) == null)
            {
                arg_41_0 = (Program.SubScriber.<>c.<>9__0_1 = new Action(Program.SubScriber.<>c.<>9.<.ctor>b__0_1));
            }
            Action action2 = arg_41_0;
            string arg_59_0 = "Target 1 = ";
            object expr_4D = action.Target;
            Console.WriteLine(arg_59_0 + ((expr_4D != null) ? expr_4D.ToString() : null));
            string arg_7B_0 = "Target 2 = ";
            object expr_6F = action2.Target;
            Console.WriteLine(arg_7B_0 + ((expr_6F != null) ? expr_6F.ToString() : null));
            Program.PrismEvents.EventTest.Subscribe(action);
            Program.PrismEvents.EventTest.Subscribe(action2);
        }

        ~SubScriber()
        {
            Console.WriteLine("SubScriber destructed");
        }
    }

我们看到“ SubScriber destructed”显示在“ Publish”之前。 有趣的是,还可以使用ILSpy查看生成的内容:

class ListPage extends StatelessWidget {
  const ListPage({Key key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('List Example'),
      ),
      body: ListView.separated(
        itemBuilder: (context, index) {
          return ListItem();
        },
        itemCount: 3,
        separatorBuilder: (_, int index) => Divider(),
      ),
    );
  }
}

class ListItem extends StatefulWidget {
  ListItem({Key key}) : super(key: key);

  @override
  _ListItemState createState() => _ListItemState();
}

class _ListItemState extends State<ListItem> {
  bool _expanded;

  @override
  void initState() {
    _expanded = false;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: () {
        setState(() {
          _expanded = !_expanded;
        });
      },
      child: Text(
        'Line1\nLine2\nLine3',
        maxLines: _expanded ? null : 1,
        softWrap: true,
        style: const TextStyle(fontSize: 22),
      ),
    );    
  }
}

我看到的区别是第二个操作具有一个静态只读字段,该字段在委托中包含一个实例...

关于, Sybaris