1

我使用以下接口作为ToFactory()绑定:

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

当我绑定时,ToFactory()我可以成功地创建类,但随后会出现内存泄漏,其中 register、unregister 和 valueGetter 参数由ConstructorArgument内部 Ninject 保存,它引用了委托中的目标/参数对象。这可以防止目标对象被 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
    {
    }
}
4

1 回答 1

3

我将此归结为 Ninject Core 中的内存泄漏:

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

于 2013-02-06T12:26:03.273 回答