【问题标题】:Perform initialization first in Ninject在 Ninject 中先执行初始化
【发布时间】:2016-07-25 06:17:30
【问题描述】:

我有这样的界面

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;
}

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

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

【问题讨论】:

  • stackoverflow.com/questions/1993397/… 这可能会有所帮助
  • each T : IPerson 的初始化逻辑是否相同?这是什么?
  • 是的,初始化将获取实例的属性,然后用数据库中的值填充。
  • 这个工作 kernel.Bind&lt;Pilot&gt;().ToMethod(ctx =&gt; ctx.Kernel.Get&lt;IProfileService&gt;().PopulateProfile&lt;Pilot&gt;()); 但我需要它是通用的。

标签: c# ninject


【解决方案1】:

您可以将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");
        }
    }
}

【讨论】:

  • 感谢@BatteryBackupUnit 的回复。如果我不知道实际的实现怎么办?我所知道的是,当有人请求实例时,Ninject 应该检查实现 IPerson 的类是否是在 Ninject 返回实例之前调用初始化方法的时间。
  • 我在想这个kernel.Bind&lt;IPerson&gt;().ToMethod(ctx =&gt; ctx.Kernel.Get&lt;IProfileService&gt;().PopulateProfile&lt;but I don't know what to pass here&gt;());是否可行
  • @DeathWish 我已经相应地调整了答案。
  • 我不知道为什么它不工作,但你的代码工作。也许我的代码有问题。但这绝对是正确的答案。非常感谢@BatteryBackupUnit :)
  • 嗨@BatteryBackupUnit,绑定生成器不工作是否有可能的原因?是否有可能是因为“ProfileService”位于不同的命名空间中,还是与 Ninject 范围有关?就像绑定生成器没有执行 PopulateProfile()。但一切都在你的代码中工作:'(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-21
  • 1970-01-01
相关资源
最近更新 更多