1

私は、具象ファクトリが具象実装の名前付きバインディングに一致するファクトリメソッドの文字列引数に基づいて実装を返すと信じている同様の質問に対するこの受け入れられた回答を研究してきました。

ファクトリが抽象ファクトリである場合に、もう少し複雑な例を適切に動作させるのに苦労しており、Ninject 規則ベースのバインディングを使用したいと考えています。次のテストを検討してください。

[Fact]
public void VehicleBuilderFactory_Creates_Correct_Builder_For_Specified_Client()
{
    // arrange
    StandardKernel kernel = new StandardKernel();
    kernel.Bind(typeof (IVehicleBuilderFactory<,>))
        .ToFactory(() => new UseFirstArgumentAsNameInstanceProvider())
        .InSingletonScope();

    kernel.Bind(scanner => scanner
                    .FromThisAssembly()
                    .SelectAllClasses()
                    .WhichAreNotGeneric()
                    .InheritedFrom(typeof(IVehicleBuilder<>))
                    .BindAllInterfaces());

    var bicycleBuilderFactory = 
        kernel.Get<IVehicleBuilderFactory<IVehicleBuilder<BlueBicycle>, BlueBicycle>>();
    string country = "Germany";
    string localizedColor = "blau";

    // act
    var builder = bicycleBuilderFactory.Create<IVehicleBuilder<BlueBicycle>>(country);
    Bicycle Bicycle = builder.Build(localizedColor);

    // assert
    Assert.IsType<BlueBicycleBuilder_Germany>(builder);
    Assert.IsType<BlueBicycle>(Bicycle);
    Assert.Equal(localizedColor, Bicycle.Color);
}

インターネットで一度見たので、たいまつとナイフでジャグリングを試みます。

public class UseFirstArgumentAsNameInstanceProvider : StandardInstanceProvider
{
    protected override string GetName(MethodInfo methodInfo, object[] arguments) {
        return methodInfo.GetGenericArguments()[0].Name + "Builder_" + (string)arguments[0];
        // ex: Germany -> 'BlueBicycle' + 'Builder_' + 'Germany' = 'BlueBicyleBuilder_Germany'
    }

    protected override ConstructorArgument[] GetConstructorArguments(MethodInfo methodInfo, object[] arguments) {
        return base.GetConstructorArguments(methodInfo, arguments).Skip(1).ToArray();
    }
}

bicycleBuilderFactoryこのエラーで割り当てようとすると、刺されて炎上します。

System.InvalidCastException was unhandled by user code
  Message=Unable to cast object of type 'Castle.Proxies.ObjectProxy' to type 'Ninject.Extensions.Conventions.Tests.IVehicleBuilderFactory`2[Ninject.Extensions.Conventions.Tests.IVehicleBuilder`1[Ninject.Extensions.Conventions.Tests.BlueBicycle],Ninject.Extensions.Conventions.Tests.BlueBicycle]'.
  Source=System.Core
  StackTrace:
       at System.Linq.Enumerable.<CastIterator>d__b1`1.MoveNext()
       at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source)
       at Ninject.ResolutionExtensions.Get[T](IResolutionRoot root, IParameter[] parameters) in c:\Projects\Ninject\ninject\src\Ninject\Syntax\ResolutionExtensions.cs:line 37
       at Ninject.Extensions.Conventions.Tests.NinjectFactoryConventionsTests.VehicleBuilderFactory_Creates_Correct_Builder_For_Specified_Client() in C:\Programming\Ninject.Extensions.Conventions.Tests\NinjectFactoryConventionsTests.cs:line 40
  InnerException: 

型を解決するために、ファクトリ メソッド引数( )とジェネリック型引数( )を使用して、メソッドとカスタム プロバイダーを使用してバインドすることは可能ですか? ToFactory() "Germany"IVehicleBiulder<BlueBicycle>, BlueBicycle

テスト用の残りのコードは、できるだけコンパクトで読みやすいものです。

public interface IVehicleBuilderFactory<T, TVehicle> 
    where T : IVehicleBuilder<TVehicle> where TVehicle : IVehicle
{
    T Create<T>(string country);
}

VehicleBuilder の実装

public interface IVehicleBuilder<T> where T : IVehicle { T Build(string localizedColor); }

abstract class BicycleBuilder<T> : IVehicleBuilder<T> where T : Bicycle
{
    public abstract T Build(string localizedColor);
}

public abstract class RedBicycleBuilder : IVehicleBuilder<RedBicycle>
{
    private readonly RedBicycle _Bicycle;
    public RedBicycleBuilder(RedBicycle Bicycle) { _Bicycle = Bicycle; }
    public RedBicycle Build(string localizedColor)
    {
        _Bicycle.Color = localizedColor;
        return _Bicycle;
    }
}
public abstract class GreenBicycleBuilder : IVehicleBuilder<GreenBicycle>
{
    private readonly GreenBicycle _Bicycle;
    public GreenBicycleBuilder(GreenBicycle Bicycle) { _Bicycle = Bicycle; }
    public GreenBicycle Build(string localizedColor)
    {
        _Bicycle.Color = localizedColor;
        return _Bicycle;
    }
}
public abstract class BlueBicycleBuilder : IVehicleBuilder<BlueBicycle>
{
    private readonly BlueBicycle _Bicycle;
    public BlueBicycleBuilder(BlueBicycle Bicycle) { _Bicycle = Bicycle; }
    public BlueBicycle Build(string localizedColor)
    {
        _Bicycle.Color = localizedColor;
        return _Bicycle;
    }
}

public class RedBicycleBuilder_USA : RedBicycleBuilder {
    public RedBicycleBuilder_USA(RedBicycle Bicycle) : base(Bicycle) { }
}

public class RedBicycleBuilder_Germany : RedBicycleBuilder {
    public RedBicycleBuilder_Germany(RedBicycle Bicycle) : base(Bicycle) { }
}
public class RedBicycleBuilder_France : RedBicycleBuilder {
    public RedBicycleBuilder_France(RedBicycle Bicycle) : base(Bicycle) { }
}
public class RedBicycleBuilder_Default : RedBicycleBuilder {
    public RedBicycleBuilder_Default(RedBicycle Bicycle) : base(Bicycle) { }
}

public class GreenBicycleBuilder_USA : GreenBicycleBuilder {
    public GreenBicycleBuilder_USA(GreenBicycle Bicycle) : base(Bicycle) { }
}
public class GreenBicycleBuilder_Germany : GreenBicycleBuilder {
    public GreenBicycleBuilder_Germany(GreenBicycle Bicycle) : base(Bicycle) { }
}
public class GreenBicycleBuilder_France : GreenBicycleBuilder {
    public GreenBicycleBuilder_France(GreenBicycle Bicycle) : base(Bicycle) { }
}
public class GreenBicycleBuilder_Default : GreenBicycleBuilder {
    public GreenBicycleBuilder_Default(GreenBicycle Bicycle) : base(Bicycle) { }
}

public class BlueBicycleBuilder_USA : BlueBicycleBuilder
{
    public BlueBicycleBuilder_USA(BlueBicycle Bicycle) : base(Bicycle) { }
}
public class BlueBicycleBuilder_Germany : BlueBicycleBuilder {
    public BlueBicycleBuilder_Germany(BlueBicycle Bicycle) : base(Bicycle) { }
}
public class BlueBicycleBuilder_France : BlueBicycleBuilder
{
    public BlueBicycleBuilder_France(BlueBicycle Bicycle) : base(Bicycle) { }
}
public class BlueBicycleBuilder_Default : BlueBicycleBuilder
{
    public BlueBicycleBuilder_Default(BlueBicycle Bicycle) : base(Bicycle) { }
}

車両の実装:

public interface IVehicle { string Color { get; set; } }
public abstract class Vehicle : IVehicle { public string Color { get; set; } }
public abstract class Bicycle : Vehicle { }
public class RedBicycle : Bicycle { }
public class GreenBicycle : Bicycle { }
public class BlueBicycle : Bicycle { }
4

1 に答える 1

1

@LukeN からのコメントに基づいて、Bicycleクラスをリファクタリングし、IColorSetter. IColorSetter実装にはジェネリックColor型があり、各実装ColorIColorLocalizer<T>.

このように、どのクラスも論理的にその責任を超えた知識を持っているようには見えません (私はそう思います)。

ただし、以下に示すリファクタリングされたクラスを使用して、Ninject カスタム インスタンス プロバイダーを使用してプロパティを選択する方法を示す方法を確認するには、これについてさらに考える必要がありますIColorLocalizer<T>。色と言語; 色はそのジェネリック型に由来し、言語は実装自体の名前に由来します。

元の投稿に質問して以来、IoC コンテナーを使用してこのような選択を行うのではなく、実装を選択するためのスイッチをプログラムでコードに配置し、未処理の異常なケースに対してデフォルトの実装を選択することにしました。しかし、それが主に私を困惑させたものを乗り越えるためなのか、それともこのように IoC コンテナーに依存するのが悪い選択であるためなのかはわかりません。

考えながら、この回答をさらに更新する必要があります。

乗り物

public abstract class Vehicle {
    public abstract string Color { get; internal set; }
    public abstract string Move();
}

public class Bicycle : Vehicle {
    public Bicycle(IColorSetter colorSetter) { colorSetter.SetColor(this); }
    public override string Color { get; internal set; }
    public override string Move() { return "Pedaling!"; }
}

カラーセッター

public interface IColorSetter { void SetColor(Vehicle vehicle); }

public class ColorSetter<T> : IColorSetter where T : Color
{
    private readonly T _color;
    public ColorSetter(T color) { _color = color; }

    public void SetColor(Vehicle vehicle) { vehicle.Color = _color.Name; }
}

カラーローカライザー

public interface IColorLocalizer<in T> where T : Color {
    void LocalizeColor(T color);
}

public class GermanBlueLocalizer : IColorLocalizer<Blue> {
    public void LocalizeColor(Blue color) { color.Name = "blau"; }
}

public class EnglishBlueLocalizer : IColorLocalizer<Blue> {
    public void LocalizeColor(Blue color) { color.Name = "blue"; }
}

public abstract class Color { public string Name { get; internal set; } }

public class Red : Color {
    public Red(IColorLocalizer<Red> colorLocalizer) {
        colorLocalizer.LocalizeColor(this); }
}

public class Green : Color {
    public Green(IColorLocalizer<Green> colorLocalizer) {
        colorLocalizer.LocalizeColor(this); }
}

public class Blue : Color {
    public Blue(IColorLocalizer<Blue> colorLocalizer) {
        colorLocalizer.LocalizeColor(this); }
}
于 2014-02-23T19:38:15.060 に答える