C# 将一个对象的方法传递给另一个对象会使第一个对象保持活动状态吗?

C# 将一个对象的方法传递给另一个对象会使第一个对象保持活动状态吗?,c#,delegates,scope,action,object-lifetime,C#,Delegates,Scope,Action,Object Lifetime,假设我有三个对象:“a”、“b”和“c”。 对象“a”和“c”是长期存在的静态引用服务单例。 对象“b”是短期的,即没有静态引用使其保持活动状态 现在假设对象“a”在其方法之一的范围内创建对象“b”的实例,例如 B b = new B(); 进一步假设类B看起来像这样: public B () { C.ActionList.Add ( SomeMethod ); } void SomeMethod () { ... } 现在,物体“b”能活多久?我的假设是,它超出了调用其构造函数的

假设我有三个对象:“a”、“b”和“c”。 对象“a”和“c”是长期存在的静态引用服务单例。 对象“b”是短期的,即没有静态引用使其保持活动状态

现在假设对象“a”在其方法之一的范围内创建对象“b”的实例,例如

B b = new B();
进一步假设类B看起来像这样:

public B ()
{
    C.ActionList.Add ( SomeMethod );
}

void SomeMethod ()
{
...
}
现在,物体“b”能活多久?我的假设是,它超出了调用其构造函数的方法的范围;具体来说,只要其方法仍在对象“c”的“ActionList”中

对吗?如果没有,它会被垃圾收集,当“c”运行其“ActionList”中的所有方法时会发生什么

附加问题:如果“b”上的方法没有命名,而是匿名的,并且在构造函数中写入,该怎么办

public B ()
{
    C.ActionList.Add ( () => {
    ...
    } );
}
具体来说,只要其方法仍在对象“c”的“ActionList”中

是的,没错。对实例方法的委托会创建对实例本身的“硬引用”,并使其保持活动状态。你的第二个问题无关紧要

请注意,这就是为什么事件订阅是.NET中“内存泄漏”的常见来源-它们在技术上不会泄漏,但事件订阅基于委托,并且具有相同的行为,因此事件订阅包含对实例的引用

如果“b”上的方法不是命名的,而是匿名的,并且是用构造函数中的lambda编写的,该怎么办

这是一样的。如果lambda使用有问题的实例的状态,它将被编译器转换为一个类型上的实例方法,该类型引用该实例,并保留一个引用。(请注意,如果某些lambda表达式不依赖于任何闭合的值、实例等,则可能会将其转换为静态方法,在这种情况下,它不会保存引用。)

在您的情况下,
的内容将决定这一点。如果您的表达式只是:
()=>{Console.WriteLine(“Foo”);}
,则它不需要关闭实例中的任何值,也不会使用有问题的实例,因此它不会持有引用。但是,如果您执行
()=>{Console.WriteLine(this.Foo);}
,它将在类型上创建一个引用
this
的方法,并使类实例保持活动状态。

+1“这就是为什么事件订阅是.NET“->和其他语言中“内存泄漏”的常见来源。在javascript崛起之初,由于没有释放过时的事件处理程序,浏览器会泄漏内存