Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/281.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 用于2+的Ninject上下文绑定;同一构造函数参数具有不同名称的依赖类_C#_Dependency Injection_Ninject_Contextual Binding - Fatal编程技术网

C# 用于2+的Ninject上下文绑定;同一构造函数参数具有不同名称的依赖类

C# 用于2+的Ninject上下文绑定;同一构造函数参数具有不同名称的依赖类,c#,dependency-injection,ninject,contextual-binding,C#,Dependency Injection,Ninject,Contextual Binding,在两个类具有相同的底层接口依赖关系,但每个类的参数命名不同的情况下,很难理解如何管理上下文绑定。下面的伪代码演示了我的情况: interface IThing { } public class Thing1 : IThing { public Thing1(string fileCode) { } } public class Thing2 : IThing { public Thing2(string fileCode) { } } interface IThi

在两个类具有相同的底层接口依赖关系,但每个类的参数命名不同的情况下,很难理解如何管理上下文绑定。下面的伪代码演示了我的情况:

    interface IThing { }
    public class Thing1 : IThing { public Thing1(string fileCode) { } }
    public class Thing2 : IThing { public Thing2(string fileCode) { } }
    interface IThingFactory { IThing CreateThing(string fileCode); }

    interface IDependentThing { }
    public class A : IDependentThing { public A(string fileCode, IThingFactory thingFactory) { } }
    public class B : IDependentThing { public B(string fileCd, IThingFactory thingFactory) { } } //How to handle binding for this dependent?
    interface IDependentThingFactory { IDependentThing CreateDependentThing(string fileCode); }

    //...

    public override void Load()
    {
        Bind<IThing>().ToMethod(ctx =>
        {
            var fileCode = ctx.Parameters.First(p => p.Name == "fileCode").GetValue(ctx, null) as string;
            IThing thing = null;

            if (fileCode == "FileType1")
            {
                Bind<Thing1>().ToSelf().WithConstructorArgument("fileCode", fileCode);
                thing = Kernel.Get<Thing1>();
            }
            else if (fileCode == "FileType2")
            {
                Bind<Thing2>().ToSelf().WithConstructorArgument("fileCode", fileCode);
                thing = Kernel.Get<Thing2>();
            }
            return thing;
        });

        Bind<IThingFactory>().ToFactory();
        Bind<IDependentThingFactory>().ToFactory();
    }

//Later...
using (TextReader tr = new StreamReader(path))
{
    string firstLine = tr.ReadLine();

    if (firstLine.Substring(838, 1) == ".")
    {
        fileCode = "FileType1";
    }
    else if (firstLine.Substring(883, 1) == ".")
    {
        fileCode = "FileType2";
    }

    //won't work for creating B
    Kernel.Get<IDependentThing>(new ConstructorArgument("fileCode", fileCode));

    //or maybe...

    //seems to eliminate my problem by allowing me to handle variations
    //in parameter names  from within A and B's ctors, but looks like it
    //requires injecting factories along the chain (see A & B ctor arguments).
    dependentThingFactory.CreateDependentThing(fileCode) 
};
interface-IThing{}
公共类Thing1:IThing{public Thing1(字符串文件代码){}
公共类Thing2:IThing{public Thing2(字符串文件代码){}
接口i ThingFactory{i Thing CreateThing(字符串文件代码);}
接口IDependentThing{}
公共类A:IDependentThing{public A(字符串文件代码,i thingFactory thingFactory){}
public类B:IDependentThing{public B(string fileCd,IThingFactory thingFactory){}//如何处理此依赖项的绑定?
接口IDependentThingFactory{IDependentThing CreateDependentThing(字符串文件代码);}
//...
公共覆盖无效负载()
{
Bind().ToMethod(ctx=>
{
var fileCode=ctx.Parameters.First(p=>p.Name==“fileCode”).GetValue(ctx,null)作为字符串;
i thing thing=null;
如果(文件代码==“文件类型1”)
{
Bind().ToSelf().WithConstructorArgument(“fileCode”,fileCode);
thing=Kernel.Get();
}
else if(fileCode==“FileType2”)
{
Bind().ToSelf().WithConstructorArgument(“fileCode”,fileCode);
thing=Kernel.Get();
}
归还物;
});
Bind().ToFactory();
Bind().ToFactory();
}
//后来。。。
使用(TextReader tr=新的StreamReader(路径))
{
字符串firstLine=tr.ReadLine();
if(第一行子字符串(838,1)==”)
{
fileCode=“FileType1”;
}
else if(第一行子字符串(883,1)=“)
{
fileCode=“FileType2”;
}
//不适用于创建B
Get(新的构造函数参数(“fileCode”,fileCode));
//或者也许。。。
//似乎通过允许我处理变化来消除我的问题
//在A和B的系数内的参数名称中,但看起来像
//需要沿着供应链注入工厂(参见A&B)。
dependentThingFactory.CreateDependentThing(文件代码)
};
fileCode
是根据对本地文件的一些分析计算出来的。一旦确定了文件类型,我希望Ninject返回处理该文件的适当对象

既然我定义的现有绑定需要具有不同名称的构造函数参数,那么如何处理
B
的绑定?一般来说,有没有更好的方法

我想我可以用
p.Name==“fileCode”| | p.Name==“fileCd”
,但我无法摆脱我做错了什么(感觉凌乱)的感觉。此外,我对按名称提取参数并不感到兴奋,我还考虑过创建一个自定义类型,与字符串参数相比,它可以为Ninject提供更具体的匹配对象。从我的立场来看,我要么只是管理多个参数名的情况,要么切换到自定义类型作为我的参数而不是字符串。

使参数注入更安全地重构,并使它们可用于整个解析上下文 您可以使用“类型匹配”或“类型化”参数,而不是“命名参数”。工厂
IInstanceProvider
可以换成另一个这样做的工厂:

kernel.Bind<IThingFactory>()
      .ToFactory(() => new TypeMatchingArgumentInheritanceInstanceProvider());
(可能您想用
enum
?)替换它)

由于您的需求更为复杂,我们将不得不稍微改变一下。 我们将创建自己的
IConstructorArgument
,以便在
上下文绑定时能够轻松地为
匹配它,并基于类型匹配注入它的值(如上所述):

现在,让我创建一些示例代码,以便稍后验证它是否有效:

public interface IThing
{
    FileCode FileCode { get; }
}

public abstract class Thing : IThing
{
    protected Thing(FileCode fileCode)
    {
        FileCode = fileCode;
    }

    public FileCode FileCode { get; private set; }
}

public class ThingFoo : Thing
{
    public ThingFoo(FileCode fileCode) : base(fileCode) { }
}

public class ThingBar : Thing
{
    public ThingBar(FileCode fileCode) : base(fileCode) { }
}

public interface IOtherThing
{
    FileCode FileCode { get; }
}

public abstract class OtherThing : IOtherThing
{
    protected OtherThing(FileCode fileCode)
    {
        FileCode = fileCode;
    }

    public FileCode FileCode { get; private set; }
}

public class OtherThingFoo : OtherThing
{
    public OtherThingFoo(FileCode fileCode) : base(fileCode) { }
}

public class OtherThingBar : OtherThing
{
    public OtherThingBar(FileCode fileCode) : base(fileCode) { }
}

public class OtherThingWrapper
{
    public OtherThingWrapper(IOtherThing otherThing)
    {
        OtherThing = otherThing;
    }

    public IOtherThing OtherThing { get; private set; }
}

public class FileProcessor
{
    public FileProcessor(IThing thing, OtherThingWrapper otherThingWrapper)
    {
        Thing = thing;
        OtherThingWrapper = otherThingWrapper;
    }

    public IThing Thing { get; private set; }
    public OtherThingWrapper OtherThingWrapper { get; private set; }
}
少了什么?工厂。我们可以将
ToFactory
绑定到定制
IInstanceProvider
上,但除非我们要用
FileCodeParameter
s创建大量工厂,否则我认为这没有意义,所以让我们保持简单:

public interface IFileProcessorFactory
{
    FileProcessor Create(FileCode fileCode);
}

internal class FileProcessorFactory : IFileProcessorFactory
{
    private readonly IResolutionRoot resolutionRoot;

    public FileProcessorFactory(IResolutionRoot resolutionRoot)
    {
        this.resolutionRoot = resolutionRoot;
    }

    public FileProcessor Create(FileCode fileCode)
    {
        return this.resolutionRoot.Get<FileProcessor>(new FileCodeParameter(fileCode));
    }
}

从何处获取连接字符串的值?这是“静态”吗。。。或者在请求的上下文中,或者..?我只是以connectionString为例。然而,我的实际代码使用的是字符串参数。我想要的可能是一种更干净的获取字符串参数的方法,但我不确定如何获取(我的预期可能不符合)。对我来说,为A的“connectionString”ctor参数设置绑定,然后还要考虑B的名为“connStr”的ctor参数似乎有问题。显然,如果我在图中添加一个C类,它可能会有“cStr”。因此,我必须不断更改代码,以考虑同一概念事物的参数命名的变化。此外,我认为我可能错误地设置了此设置,因为我对需要传递给链中多个依赖项的参数的工作方式存在误解。看起来,如果我将A和B的因子更改为接受IThingFactory而不是IThing,那么A和B的因子中参数命名的变化可以在那里的因子中处理,而不是在绑定代码中处理。无论如何,如果我错了,请纠正我,或者建议一个更好的方法,我仍然在学习Ninject的诀窍。但是字符串参数(值)是从哪里来的呢?它不是凭空产生的,是吗?;-)您的问题涉及到几个技术“问题”:1)传递参数,2)进一步传递参数,3)根据上下文信息选择类型。现在,根据参数的来源以及该信息的有效期,我们可以完全改变如何执行3)的方法,可能会影响1)和2)或使2)
public interface IThing
{
    FileCode FileCode { get; }
}

public abstract class Thing : IThing
{
    protected Thing(FileCode fileCode)
    {
        FileCode = fileCode;
    }

    public FileCode FileCode { get; private set; }
}

public class ThingFoo : Thing
{
    public ThingFoo(FileCode fileCode) : base(fileCode) { }
}

public class ThingBar : Thing
{
    public ThingBar(FileCode fileCode) : base(fileCode) { }
}

public interface IOtherThing
{
    FileCode FileCode { get; }
}

public abstract class OtherThing : IOtherThing
{
    protected OtherThing(FileCode fileCode)
    {
        FileCode = fileCode;
    }

    public FileCode FileCode { get; private set; }
}

public class OtherThingFoo : OtherThing
{
    public OtherThingFoo(FileCode fileCode) : base(fileCode) { }
}

public class OtherThingBar : OtherThing
{
    public OtherThingBar(FileCode fileCode) : base(fileCode) { }
}

public class OtherThingWrapper
{
    public OtherThingWrapper(IOtherThing otherThing)
    {
        OtherThing = otherThing;
    }

    public IOtherThing OtherThing { get; private set; }
}

public class FileProcessor
{
    public FileProcessor(IThing thing, OtherThingWrapper otherThingWrapper)
    {
        Thing = thing;
        OtherThingWrapper = otherThingWrapper;
    }

    public IThing Thing { get; private set; }
    public OtherThingWrapper OtherThingWrapper { get; private set; }
}
public interface IFileProcessorFactory
{
    FileProcessor Create(FileCode fileCode);
}

internal class FileProcessorFactory : IFileProcessorFactory
{
    private readonly IResolutionRoot resolutionRoot;

    public FileProcessorFactory(IResolutionRoot resolutionRoot)
    {
        this.resolutionRoot = resolutionRoot;
    }

    public FileProcessor Create(FileCode fileCode)
    {
        return this.resolutionRoot.Get<FileProcessor>(new FileCodeParameter(fileCode));
    }
}
public class Test
{
    [Fact]
    public void FactMethodName()
    {
        var fooFileCode = new FileCode("foo");
        var barFileCode = new FileCode("bar");

        var kernel = new StandardKernel();
        kernel
            .Bind<IFileProcessorFactory>()
            .To<FileProcessorFactory>();

        kernel
            .Bind<IThing>()
            .To<ThingFoo>()
            .WhenFileCode(fooFileCode);
        kernel
            .Bind<IThing>()
            .To<ThingBar>()
            .WhenFileCode(barFileCode);

        kernel
            .Bind<IOtherThing>()
            .To<OtherThingFoo>()
            .WhenFileCode(fooFileCode);
        kernel
            .Bind<IOtherThing>()
            .To<OtherThingBar>()
            .WhenFileCode(barFileCode);


        var fileProcessor = kernel.Get<IFileProcessorFactory>().Create(barFileCode);
        fileProcessor.Thing.Should().BeOfType<ThingBar>();
        fileProcessor.Thing.FileCode.Should().Be(barFileCode);
        fileProcessor.OtherThingWrapper.OtherThing.Should().BeOfType<OtherThingBar>();
        fileProcessor.OtherThingWrapper.OtherThing.FileCode.Should().Be(barFileCode);
    }
}

public static class BindingExtensionsForFileCodes
{
    public static IBindingInNamedWithOrOnSyntax<T> WhenFileCode<T>(
        this IBindingWhenSyntax<T> syntax,
        FileCode fileCode)
    {
        return syntax.When(req => req
            .Parameters
            .OfType<FileCodeParameter>()
            .Single()
            .FileCode.Value == fileCode.Value);
    }
}
using FluentAssertions;
using Ninject;
using Ninject.Activation;
using Ninject.Parameters;
using Ninject.Planning.Targets;
using Ninject.Syntax;
using System.Linq;
using Xunit;

namespace NinjectTest.ParameterContextual
{
    public class FileCode
    {
        public FileCode(string value)
        {
            Value = value;
        }

        public string Value { get; private set; }
    }

    public interface IThing
    {
        FileCode FileCode { get; }
    }

    public abstract class Thing : IThing
    {
        protected Thing(FileCode fileCode)
        {
            FileCode = fileCode;
        }

        public FileCode FileCode { get; private set; }
    }

    public class ThingFoo : Thing
    {
        public ThingFoo(FileCode fileCode) : base(fileCode) { }
    }

    public class ThingBar : Thing
    {
        public ThingBar(FileCode fileCode) : base(fileCode) { }
    }

    public interface IOtherThing
    {
        FileCode FileCode { get; }
    }

    public abstract class OtherThing : IOtherThing
    {
        protected OtherThing(FileCode fileCode)
        {
            FileCode = fileCode;
        }

        public FileCode FileCode { get; private set; }
    }

    public class OtherThingFoo : OtherThing
    {
        public OtherThingFoo(FileCode fileCode) : base(fileCode) { }
    }

    public class OtherThingBar : OtherThing
    {
        public OtherThingBar(FileCode fileCode) : base(fileCode) { }
    }

    public class OtherThingWrapper
    {
        public OtherThingWrapper(IOtherThing otherThing)
        {
            OtherThing = otherThing;
        }

        public IOtherThing OtherThing { get; private set; }
    }

    public class FileProcessor
    {
        public FileProcessor(IThing thing, OtherThingWrapper otherThingWrapper)
        {
            Thing = thing;
            OtherThingWrapper = otherThingWrapper;
        }

        public IThing Thing { get; private set; }
        public OtherThingWrapper OtherThingWrapper { get; private set; }
    }

    public interface IFileProcessorFactory
    {
        FileProcessor Create(FileCode fileCode);
    }

    internal class FileProcessorFactory : IFileProcessorFactory
    {
        private readonly IResolutionRoot resolutionRoot;

        public FileProcessorFactory(IResolutionRoot resolutionRoot)
        {
            this.resolutionRoot = resolutionRoot;
        }

        public FileProcessor Create(FileCode fileCode)
        {
            return this.resolutionRoot.Get<FileProcessor>(new FileCodeParameter(fileCode));
        }
    }

    public class Test
    {
        [Fact]
        public void FactMethodName()
        {
            var fooFileCode = new FileCode("foo");
            var barFileCode = new FileCode("bar");

            var kernel = new StandardKernel();
            kernel
                .Bind<IFileProcessorFactory>()
                .To<FileProcessorFactory>();

            kernel
                .Bind<IThing>()
                .To<ThingFoo>()
                .WhenFileCode(fooFileCode);
            kernel
                .Bind<IThing>()
                .To<ThingBar>()
                .WhenFileCode(barFileCode);

            kernel
                .Bind<IOtherThing>()
                .To<OtherThingFoo>()
                .WhenFileCode(fooFileCode);
            kernel
                .Bind<IOtherThing>()
                .To<OtherThingBar>()
                .WhenFileCode(barFileCode);


            var fileProcessor = kernel.Get<IFileProcessorFactory>().Create(barFileCode);
            fileProcessor.Thing.Should().BeOfType<ThingBar>();
            fileProcessor.Thing.FileCode.Should().Be(barFileCode);
            fileProcessor.OtherThingWrapper.OtherThing.Should().BeOfType<OtherThingBar>();
            fileProcessor.OtherThingWrapper.OtherThing.FileCode.Should().Be(barFileCode);
        }
    }

    internal class FileCodeParameter : IConstructorArgument
    {
        private readonly FileCode fileCode;

        public FileCodeParameter(FileCode fileCode)
        {
            this.fileCode = fileCode;
        }

        public string Name { get { return "File Code Parameter"; } }

        public bool ShouldInherit { get { return true; } }

        public FileCode FileCode  { get { return this.fileCode; } }

        public bool Equals(IParameter other)
        {
            var otherFileCodeParameter = other as FileCodeParameter;
            if (otherFileCodeParameter == null)
            {
                return false;
            }

            return otherFileCodeParameter.fileCode == this.fileCode;
        }

        public object GetValue(IContext context, ITarget target)
        {
            return this.fileCode;
        }

        public bool AppliesToTarget(IContext context, ITarget target)
        {
            return target.Type == typeof(FileCode);
        }
    }

    public static class BindingExtensionsForFileCodes
    {
        public static IBindingInNamedWithOrOnSyntax<T> WhenFileCode<T>(
            this IBindingWhenSyntax<T> syntax,
            FileCode fileCode)
        {
            return syntax.When(req => req
                .Parameters
                .OfType<FileCodeParameter>()
                .Single()
                .FileCode.Value == fileCode.Value);
        }
    }
}