如何根据最终的注入链目标注入实例?

问题描述 投票:1回答:1

我有一些类:X1 <- Y <- Z <- Config(箭头表示通过构造函数注入)和X2 <- Y <- Z <- ConfigZ需要一些配置(Config类),但是实例取决于最终类型:X1X2(键入自身或以某种方式定义的键)。在此示例中,每个YZConfig类应该有两个不同的实例。

如何根据最终使用位置(ConfigZ)在X1中使用不同的X2

    class X1
    {
        public X1(Y y)
        {
            int c = y.Z.Config.C; // This config variable is connected with X1.
        }
    }

    class X2
    {
        public X2(Y y)
        {
            int c = y.Z.Config.C; // This config variable is different than the one for X1.
        }
    }

    class Y
    {
        public Z Z { get; }

        public Y(Z z)
        {
            Z = z;
        }
    }


    class Z
    {
        public Config Config { get; }

        public Z(Config config)
        {
            Config = config;
        }
    }

    class Config
    {
        public int C { get; set; }
    }

我可以像下面那样做,但是看起来很腥,很臭(一个粗糙的例子):

    Bind<Config>().ToMethod(x =>
    {
        // Return proper config object depending on the classes found in the injection chain...
        IRequest req = x.Request;
        while (req != null)
        {
            if (req.Service.UnderlyingSystemType == typeof(X1))
            {
                return configForX1;
            }

            if (req.Service.UnderlyingSystemType == typeof(X2))
            {
                return configForX2;
            }

            req = req.ParentRequest;
        }

        throw new Exception("Oh no.");
    });

或者要使其不那么腥:

    class X1
    {
        public X1([Named("X1")] Config config, Y y)
        {
            y.SetConfig(config);
        }
    }

    class Y
    {
        private readonly Z _z;

        public Y(Z z)
        {
            _z = z;
        }

        public void SetConfig(Config config)
        {
            _z.SetConfig(config);
        }
    }

    class Z
    {
        private Config _config;

        public void SetConfig(Config config)
        {
            _config = config;
        }
    }

    Bind<MetricsApiConfiguration>().To().Named("X1");
    Bind<MetricsApiConfiguration>().To().Named("X2");

还有其他(更好的)主意吗?

c# dependency-injection ninject
1个回答
0
投票

WhenInjectedInto已关闭,但是正如您所指出的,仅查看当前请求。我创建了扩展方法来解决这个确切的用例:

    public static IBindingInNamedWithOrOnSyntax<T> WhenAnyAncestorIs<T>(this IBindingWhenSyntax<T> binding, params Type[] types)
    {
        bool Matches(IRequest request)
        {
            Type target = request.Target?.Member?.ReflectedType;
            return (target != null && types.Any(t => t == target))
                || (request.ParentRequest != null && Matches(request.ParentRequest));
        }

        return binding.When(Matches);
    }

并且使用类似:

Bind<IConfigSource>().To<DataConfigSource>()
    .WhenAnyAncestorIs(
        typeof(DataConfigurationRepository),
        typeof(ManifestRepository),
        typeof(DataManager)
    )
    .InSingletonScope();

对于不使用这些类型的请求,您将需要附加绑定。

© www.soinside.com 2019 - 2024. All rights reserved.