Ninject Factory扩展内存泄漏?

时间:2013-02-05 12:16:39

标签: c# .net ninject ninject-extensions

我使用以下界面作为ToFactory()绑定:

public interface ISamplerFactory
{
    ISampler Create(Action<EventHandler<ValueChangedEventArgs>> register, Action<EventHandler<ValueChangedEventArgs>> unregister, Func<decimal?> valueGetter);
}

当我绑定ToFactory()时,我可以成功创建类但是我得到内存泄漏,其中register,unregister和valueGetter参数由Ninject内的ConstructorArgument保存,引用目标/参数委托内的对象。这使得目标对象无法获得GC。如果这有所不同,我也在使用ContextPreservation扩展。 (参见下面的完整示例代码)

当我删除“ToFactory()”绑定并创建标准工厂类时,它可以正常工作。

public class SamplerFactory : ISamplerFactory
{
    private readonly IDistributionResolver _resolverFactory;

    public SamplerFactory(IDistributionResolverFactory resolverFactory)
    {
        _resolverFactory = resolverFactory;
    }

    ISampler Create(Action<EventHandler<ValueChangedEventArgs>> register, Action<EventHandler<ValueChangedEventArgs>> unregister, Func<decimal?> valueGetter)
    {
        return new SpecificSampler(_resolverFactory, register, unregister, valueGetter);
    }
}

代理中的目标对象已成功GC。

我做错了什么或者工厂扩展是否意味着处理这些更复杂的参数?我假设如果我使用.WithConstructorArgument我会得到相同的结果。

编辑:添加了所有必要的绑定并重写了我的示例代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication
{
    using System;
    using Ninject;
    using Ninject.Extensions.ContextPreservation;
    using Ninject.Extensions.Factory;

    public class Program
    {
        static void Main(string[] args)
        {
            new Program().Run();
        }

        public void Run()
        {
            var kernel = new StandardKernel(new NinjectSettings() { LoadExtensions = false });
            kernel.Load(new FuncModule());
            kernel.Load(new ContextPreservationModule());

            kernel.Bind<IDistributionResolver>().To<DistributionResolver>(); // This is a constructor-less object.
            kernel.Bind<ISampler>().To<SpecificSampler>();
            kernel.Bind<ISamplerFactory>().ToFactory();
            kernel.Bind<IInjected>().To<Injected>();
            kernel.Bind<IDistributionResolver>().To<DistributionResolver>();
            kernel.Bind<IDistributionResolverFactory>().ToFactory();


            var s = new SomeObject();
            var weakS = new WeakReference(s);

            var factory = kernel.Get<ISamplerFactory>();

            var sampler = CreateInstance(factory, s);

            s = null;
            factory = null;
            sampler = null;

            GC.Collect();

            if (weakS.IsAlive)
                throw new Exception();
        }

        private ISampler CreateInstance(ISamplerFactory factory, SomeObject someObject)
        {
            var x = factory.Create(y => someObject.Do += y, z => someObject.Do -= z, () => someObject.Query());

            if (x == null)
                throw new Exception();

            return x;
        }


        public class SomeObject
        {
            public event EventHandler<ValueChangedEventArgs> Do;

            public decimal? Query()
            {
                return 0;
            }
        }

        public class SpecificSampler : ISampler
        {
            private readonly IDistributionResolverFactory resolver;
            private readonly Action<EventHandler<ValueChangedEventArgs>> register;
            private readonly Action<EventHandler<ValueChangedEventArgs>> unregister;
            private Func<decimal?> _valueGetter;

            public SpecificSampler(
                IDistributionResolverFactory resolver, // This is injected
                Action<EventHandler<ValueChangedEventArgs>> register, // The rest come from the factory inputs
                Action<EventHandler<ValueChangedEventArgs>> unregister,
                Func<decimal?> valueGetter)
            {
                this.resolver = resolver;
                this.register = register;
                this.unregister = unregister;
                _valueGetter = valueGetter;
                // Do Stuff;
            }
        }

        public class ValueChangedEventArgs : EventArgs
        {
        }

        public interface ISamplerFactory
        {
            ISampler Create(Action<EventHandler<ValueChangedEventArgs>> register, Action<EventHandler<ValueChangedEventArgs>> unregister, Func<decimal?> valueGetter);
        }

        public interface IDistributionResolverFactory
        {
            IDistributionResolver Create(IDictionary<string, string> picked);
        }

        public interface IDistributionResolver
        {

        }

        private class DistributionResolver : IDistributionResolver
        {
            readonly IInjected _i;
            readonly IDictionary<string, string> _picked;

            public DistributionResolver(IInjected i, IDictionary<string, string> picked)
            {
                _i = i;
                _picked = picked;
            }
        }

        public interface ISampler
        {
        }
    }

    public interface IInjected
    {
    }

    class Injected : IInjected
    {
    }
}

1 个答案:

答案 0 :(得分:3)

我将此跟踪到Ninject Core中的内存泄漏:

https://github.com/ninject/ninject/issues/74