Полиморфизм и внедрение зависимостей, как выбрать дочерний класс, не создавая его - PullRequest
0 голосов
/ 19 мая 2018

В DI я всегда использовал подход с инжекцией конструктора.Также с DI класс зависимостей внедряется в вызывающий класс, нет необходимости создавать экземпляр класса зависимостей.

Рассмотрим этот код ниже, мне нужно определить, какой конкретный класс использовать.Как выбрать правильный конкретный класс, не создавая экземпляр класса вручную (поскольку с DI инжектор делает это за вас)?Код полностью написан от руки, извините за любую опечатку:)

public interface IMyInterface
    {
        void DoSomething();
    }

public class SuperClass : IMyInterface
{
    private DependencyClass _dependency;
    public SuperClass(DependencyClass dependency)
    {
         _dependency = dependency;
    }

    public abstract void DoSomething();

}

public class ChildClassCommon : SuperClass
{
    private DependencyClass _dependency;
    public ChildClassCommon(DependencyClass dependency)
    {
         _dependency = dependency;
    }

    public override void DoSomething()
    {
    }
}

public class ChildClassSpecial : SuperClass
{
    private DependencyClass _dependency;
    public ChildClassSpecial(DependencyClass dependency)
    {
         _dependency = dependency;
    }

    public override void DoSomething()
    {
    }
}


public class Main()
{
    private IMyInterface _myClass;

    public Main(IMyInterface myClass)
    {
        _myClass = myClass;
    }

    public void Selector(string recordType)
    {
        if(recordType == "Common")
        {
             // without DI, i would normally just do a new here to 
             // instantiate the concrete class, but with DI, I shouldnt be
             // instantiating a new instance, but how do I select which
             // concrete class to use?
            _myClass = new ChildClassCommon(DependencyClass dependency);
        }
        else if (recordType == "Special")
        {
            _myClass = new ChildClassSpecial(DependencyClass dependency);
        }

        _myClass.DoSomething();
    }
}

Ответы [ 4 ]

0 голосов
/ 19 мая 2018

Я идиот, я легко могу разыграть его.Ответил на мой вопрос во время просмотра телевизора: D

if(recordType == "Common")
        {

            ((ChildClassCommon)_myClass).DoSomething();
        }
        else if (recordType == "Special")
        {
            ((ChildClassSpecial)_myClass).DoSomething();
        }
0 голосов
/ 19 мая 2018

Если я прочитал это правильно, тогда typeof() будет вариантом для ссылки на ваш конкретный тип, если вы не хотите создавать экземпляр объекта в это время.

public static Type Selector(string recordType)
{
        Type concreteType;

        switch (recordType)
        {
            case "Common":
                concreteType = typeof(ChildClassCommon);
                break;
            case "Special":
                concreteType = typeof(ChildClassSpecial);
                break;
            default:
                concreteType = null;
                break;
        }

        return concreteType;
}

Поймите, хотя, вВ какой-то момент вам нужно создать экземпляр объекта, чтобы иметь возможность использовать его в вашем приложении.Таким образом, в приведенном выше примере для создания экземпляра вы можете использовать Reflection с вашим параметром DI, например, так:

var type = Selector("Common");
var myObject = (IMyInterface) Activator.CreateInstance(type, new object[] { dependency });

MSDN:

typeof()

Type

0 голосов
/ 19 мая 2018

Вы можете зарегистрировать все реализованные классы и классы фабрики.После чего вы можете разрешить фабричный класс.Когда у вас есть фабричный класс, вы генерируете нужный объект с определенным правилом генерации.

Я использую Autofac для инструмента DI в этом примере

class Program
{
    public class DependencyClass { }

    public interface IMyInterface
    {
        void DoSomething();
    }

    public abstract class SuperClass : IMyInterface
    {
        protected DependencyClass _dependency;
        public SuperClass(DependencyClass dependency)
        {
            _dependency = dependency;
        }

        abstract public void DoSomething();
    }

    public class ChildClassCommon : SuperClass
    {
        public ChildClassCommon(DependencyClass dependency) : base(dependency){}

        public override void DoSomething(){}
    }

    public class ChildClassSpecial : SuperClass
    {
        public ChildClassSpecial(DependencyClass dependency) : base(dependency){}

        public override void DoSomething(){}
    }

    public class MyInterfaceFactory
    {
        private IEnumerable<IMyInterface> _myInterfaces;
        public MyInterfaceFactory(IEnumerable<IMyInterface> myInterfaces)
        {
            _myInterfaces = myInterfaces;
        }

        public IMyInterface Generate(string rule)
        {
            IMyInterface myObject;
            if (rule == "a")
                myObject = _myInterfaces.First(x => x is ChildClassCommon);
            else
                myObject = _myInterfaces.First(x => x is ChildClassSpecial);
            return myObject;
        }
    }

    // Injection run in this
    static void Main(string[] args)
    {
        var builder = new ContainerBuilder();

        builder.RegisterType<DependencyClass>().AsSelf();


        builder.RegisterType<MyInterfaceFactory>().AsSelf();

        var assembly = Assembly.GetExecutingAssembly();
        builder
            .RegisterAssemblyTypes(assembly)
            .AssignableTo<IMyInterface>()
            .AsImplementedInterfaces();

        var container = builder.Build();

        var factory = container.Resolve<MyInterfaceFactory>();
        IMyInterface myInterface = factory.Generate("a");

        Console.WriteLine(myInterface.GetType());

        Console.ReadKey();
    }
}
0 голосов
/ 19 мая 2018

Я не уверен, хорошо ли я вас понял, но если вы не хотите создавать экземпляр класса и хотите его использовать, возможно, попробуйте с отражением?Вы можете получить указанный класс и затем вызывать его методы.

...