1

我使用 C# 和 Autofac 4.9.4。我有一个 Autofac 模块,它连接到 IComponentRegistration.Activated 事件。它查找某些类的激活实例并将它们注册到某个管理器类中。当然,此注册应限于受影响对象的生命周期。因此模块需要知道对象何时被容器丢弃,然后从管理器中注销它。否则我会产生内存泄漏。当我向 autofac ContainerBuilder 注册一个类时,有一个 OnRelease-Method,但这不是正确的地方;我需要模块内的这样一个事件。

具体代码如下所示:

using Autofac;
using Autofac.Core;

namespace De.Gedat.Foundation.Bl.IoC
{

    public class ResetManagerModule : Module
    {
        protected override void AttachToComponentRegistration(
            IComponentRegistry componentRegistry,
            IComponentRegistration registration)
        {
            registration.Activated += (sender, e) =>
                RegisterToResetManager(e.Instance, e.Context);
            registration.Released += ???
        }

        private void RegisterToResetManager(object instance, IComponentContext context)
        {
            // Every IAutoRegisteredResettable object created by IoC will be picked up:
            var resettable = instance as IAutoRegisteredResettable;
            if (resettable == null)
                return;
            // Get the singleton IResetManager...
            var resetManager = context.Resolve<IResetManager>();
            // ...and register the instance with it:
            resetManager.RegisterInstance(resettable);

            // ...and on resettable's end-of-lifetime we would have to call:
            //resetManager.UnregisterInstance(resettable)
            //...but not at this point when the instance has just been created!
        }
    }
}

当一个物体被丢弃时,我怎样才能引起注意?

4

2 回答 2

0

假设一个生命周期范围,我们希望让 autofac 为我们处理所有的处理,所以最好用 using 语句包装上下文,但它也会处理resettable并且我们将无法调用resetManager.UnregisterInstance(resettable).

为了不释放您的resettable实例,并且在释放生命周期范围时仍然让 autofac 处理所有的释放,我们可以告诉 autofac 我们要使用ExternallyOwned( doc ) 自己处理它,并且在finally语句中我们可以调用resetManager.UnregisterInstance(resettable)然后手动处置实例。

private void RegisterToResetManager(object instance, IComponentContext context)
{
    var resettable = instance as IAutoRegisteredResettable;
    if (resettable == null)
        return;
    var resetManager = context.Resolve<IResetManager>();

    try
    {
        resetManager.RegisterInstance(resettable).ExternallyOwned();
    }
    finally
    {
        resetManager.UnregisterInstance(resettable);
        resettable.Dispose();
    }
}
于 2019-12-01T21:16:14.820 回答
0

我们提出了以下完美的解决方案:

public class ResetManagerAutofacModule : Module
{
    protected override void AttachToComponentRegistration(
        IComponentRegistryBuilder componentRegistryBuilder,
        IComponentRegistration registration)
    {
        registration.Activated += (sender, e) =>
            RegisterToResetManager(e.Instance, e.Context);
    }

    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterType<ResetManager>().As<IResetManager>().SingleInstance();
        // Because there are no module events for the end-of-lifetime of objects,
        // we use a disposable class as a helper to get informed about disposal
        // (declaration see below):
        builder
            .RegisterType<DisposeObserver>()
            .InstancePerDependency(); // important!!!
    }

    private void RegisterToResetManager(object instance, IComponentContext context)
    {
        var resettable = instance as IAutoRegisteredResettable;
        if (resettable == null)
            return;
        var resetManager = context.Resolve<IResetManager>();
        // Hook the object on the manager:
        resetManager.RegisterInstance(resettable);
        // Get a new instance of our dispose helper class from the container
        // which has the same lifetime as "instance" because DisposeObserver
        // is registered as InstancePerDependency.
        var disposableWithCallback = context.Resolve<DisposeObserver>();
        // When this helper is disposed, we know that the lifetime of "instance" is over.
        disposableWithCallback.DisposingCallback =
            // So we can unhook it from the manager:
            () => resetManager.UnregisterInstance(resettable);
    }

    public class DisposeObserver : IDisposable
    {
        public Action DisposingCallback { get; set; }
        public void Dispose()
        {
            DisposingCallback?.Invoke();
            DisposingCallback = null;
        }
    }
}
于 2020-08-18T07:32:51.580 回答