在 Ninject 中首先执行初始化

Perform initialization first in Ninject

我有这样的界面

public interface IPerson { }

和实现

public class Fireman : IPerson
{
    public string Name { get; set; }
    public bool WithAssignedTruck { get; set; }
    ...
}

public class Pilot : IPerson
{
    public string Name { get; set; }
    public int Age { get; set; }
    ...
}

并将它们传递给构造函数

public class Registration : IRegistration
{
    private readonly Fireman _fireman;
    private readonly Pilot _pilot;

    public Registration(Pilot pilot, Fireman fireman)
    {
         this._fireman = fireman;
         this._pilot = pilot;
    }    
}

这是初始化方法的样子。

public T PopulateProfile<T>() where T : IPerson, new()
{
    var personProfile = Activator.CreateInstance<T>();
    ...

    return personProfile;
}

请注意,此代码只是示例。

我有一个方法可以设置来自数据库的这些 class 中每个 属性 的值。我需要做的是,当我向 Ninject 询问任何实现 IPerson 接口的 class 时,Ninject 应该首先执行该方法,因此, Ninject 将 return 初始化为 class。希望你能帮帮我。谢谢。

您可以将 Ninject.Extensions.ConventionsIBindingGenerator 结合使用,从而生成 ToMethod 绑定:

绑定生成器

internal class PersonBindingGenerator : IBindingGenerator
{
    private static readonly MethodInfo PopulateOpenGenericMethodInfo =
        typeof(IProfileService).GetMethod("PopulateProfile");

    public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(
        Type type,
        IBindingRoot bindingRoot)
    {
        yield return bindingRoot
            .Bind(type)
            .ToMethod(x => CreatePerson(x.Kernel.Get<IProfileService>(), type));
    }

    private static object CreatePerson(
        IProfileService profileService,
        Type type)
    {
        var closedGeneric = PopulateOpenGenericMethodInfo.MakeGenericMethod(type);
        return closedGeneric.Invoke(profileService, new object[0]);
    }
}

绑定

kernel.Bind<IProfileService>().To<ProfileService>();

kernel.Bind(s => s
    .FromThisAssembly()
    .IncludingNonePublicTypes()
    .SelectAllClasses()
    .InheritedFrom<IPerson>()
    .BindWith<PersonBindingGenerator>());

测试

完整的测试代码供参考。

using FluentAssertions;
using Ninject;
using Ninject.Extensions.Conventions;
using Ninject.Extensions.Conventions.BindingGenerators;
using Ninject.Syntax;
using System;
using System.Collections.Generic;
using System.Reflection;
using Xunit;

namespace NinjectTest.SO36424126
{
    public interface IPerson
    {
        string SomeValue { get; set; }
    }

    class BarPerson : IPerson
    {
        public string SomeValue { get; set; }
    }

    class FooPerson : IPerson
    {
        public string SomeValue { get; set; }
    }

    public interface IProfileService
    {
        T PopulateProfile<T>() 
            where T : IPerson, new();
    }

    internal class ProfileService : IProfileService
    {
        public T PopulateProfile<T>()
            where T : IPerson, new()
        {
            var personProfile = Activator.CreateInstance<T>();
            personProfile.SomeValue = "initialized";
            return personProfile;
        }
    }

    internal class PersonBindingGenerator : IBindingGenerator
    {
        private static readonly MethodInfo PopulateOpenGenericMethodInfo = typeof(IProfileService).GetMethod("PopulateProfile");

        public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
        {
            yield return bindingRoot
                .Bind(type)
                .ToMethod(x => CreatePerson(x.Kernel.Get<IProfileService>(), type));
        }

        private static object CreatePerson(IProfileService profileService, Type type)
        {
            var closedGeneric = PopulateOpenGenericMethodInfo.MakeGenericMethod(type);
            return closedGeneric.Invoke(profileService, new object[0]);
        }
    }

    public class Test
    {
        [Fact]
        public void Foo()
        {
            var kernel = new StandardKernel();

            kernel.Bind<IProfileService>().To<ProfileService>();

            kernel.Bind(s => s
                .FromThisAssembly()
                .IncludingNonePublicTypes()
                .SelectAllClasses()
                .InheritedFrom<IPerson>()
                .BindWith<PersonBindingGenerator>());

            kernel.Get<BarPerson>().SomeValue.Should().Be("initialized");
        }
    }
}