C#의 학습 종속성 주입(IoC) 컨테이너

14403 단어 csharpbeginners

소개



C# 초보자였을 때 어디에서나 "DI 컨테이너"라는 단어를 보곤 했습니다. 마침내 종속성 주입 사용에 익숙해지고 있으며 DI 컨테이너를 다시 방문할 시간입니다.

의존성 주입



종속성 주입은 소프트웨어에서 느슨한 결합을 달성하는 데 매우 중요한 기술입니다.
아래에 무언가를 작성하는 대신 클래스 간의 긴밀한 결합을 제거할 수 있습니다.

public class Cat
{
    public void CheckFood()
    {
        Food catfood = new Food("cat food");
        Console.WriteLine("I am eating " + catfood.Name );
    }
}

public class Food
{
    public string Name {get;set;}

    public Food(string foodName)
    {
        this.Name = foodName;
    }
}


이 경우 Cat 클래스는 Food에 의존합니다.
생성자로부터 종속성을 주입하여 종속성을 개선합니다.

public class Cat
{
    private Food food;
    public Cat(Food food)
    {
        this.food = food;
    }
    public void CheckFood()
    {
        Console.WriteLine("I am eating " + food.Name );
    }
}

public class Food
{
    public string Name {get;set;}

    public Food(string foodName)
    {
        this.Name = foodName;
    }
}


차이점은 음식 인스턴스가 cat 클래스에서 인스턴스화되지 않고 음식 인스턴스가 생성자를 통해 주입된다는 것입니다.

종속성 주입 컨테이너



이 종속성 주입 기술을 계속 사용할 수 있지만 클래스의 인스턴스화는 번거로울 수 있습니다. DI 컨테이너 프레임워크는 이 작업에 도움이 될 수 있습니다.

DI Container를 통한 간단한 인터페이스 구현



개와 고양이 클래스가 있는 IAnimal 인터페이스를 고려해 봅시다. 그들은 다른 소리를 내고 우리는 그것들을 듣고 싶어합니다.

DI 컨테이너 없음




    public interface IAnimal
    {
        void noise();
    }

    public class Cat : IAnimal
    {
        public void noise()
        {
            Console.WriteLine("meow");
        }
    }

    public class Dog : IAnimal
    {
        public void noise()
        {
            Console.WriteLine("bark!");
        }
    }



컨테이너 없이 인스턴스화하는 것은 매우 쉽습니다.

IAnimal cat = new Cat();
IAnimal dog = new Dog();
cat.noise();
dog.noise();


그게 다야!

DI 컨테이너 포함




container.RegisterType<IAnimal, Cat>();
container.RegisterType<IAnimal, Dog>();

IAnimal cat = container.Resolve<Cat>();
cat.noise();
IAnimal dog = container.Resolve<Dog>();
dog.noise();


IAnimal과 Cat 사이의 관계를 등록할 수 있습니다. 우리는 개 클래스에 대해서도 똑같이 할 수 있습니다.
관계가 컨테이너에 등록되어 있으므로 Resolve 메서드를 호출하여 객체를 생성할 수 있습니다.

다소 복잡한 경우



위의 예는 너무 쉽고 DI 컨테이너의 유용성을 실제로 보여주지 않습니다.

DI 컨테이너 없음



9개의 컨테이너에 의존하는 개체가 있고 이를 구현하기 위해 DI를 사용하려는 경우 어떻게 해야 합니까?

생성자는 다음과 같습니다.

ParentObj parentObj = new ParentObj(new Obj1(new Obj4(), new Obj5(new Obj8())), new Obj2(new Obj6(new Obj8())), new Obj3(new Obj7(new Obj9())));


이 개체를 한 번만 사용해야 하는 경우에는 괜찮지만 이와 같은 것을 계속해서 사용해야 할 수도 있습니다.

DI 컨테이너 포함



DI 컨테이너를 사용하면 적절하게 연결한 후 인스턴스화 부분을 간단하게 만들 수 있습니다.
배선 과정은 지루할 수 있지만 한 번만 하면 됩니다.

container.RegisterType<Obj8>();
//setup obj1
container.RegisterType<Obj4>();
container.RegisterType<Obj5>(new InjectionConstructor(container.Resolve<Obj8>()));
container.RegisterType<Obj1>(new InjectionConstructor(container.Resolve<Obj4>(), container.Resolve<Obj5>()));

//setup obj2
container.RegisterType<Obj6>(new InjectionConstructor(container.Resolve<Obj8>()));
container.RegisterType<Obj2>(new InjectionConstructor(container.Resolve<Obj6>()));

//setup obj3
container.RegisterType<Obj9>();
container.RegisterType<Obj7>(new InjectionConstructor(container.Resolve<Obj9>()));
container.RegisterType<Obj3>(new InjectionConstructor(container.Resolve<Obj7>()));

container.RegisterType<ParentObj>(new InjectionConstructor(container.Resolve<Obj1>(), container.Resolve<Obj2>(), container.Resolve<Obj3>()));


이제 부모 개체를 생성할 수 있습니다.

ParentObj containerParentObj = container.Resolve<ParentObj>();


이 예제에서는 간단한 개체를 사용했지만 실제로는 각 개체가 복잡할 수 있으며 이는 낮은 가독성의 고통을 크게 줄일 수 있습니다.

용기를 어디에 둘까



컨테이너 배치에 대해 몇 가지 질문이 있습니다. 모든 클래스가 제대로 연결되면 컨테이너가 우리를 위해 많은 작업을 수행할 수 있다는 것을 이해했습니다. 컨테이너가 있으면 컨테이너를 전달해야 합니까??
컨테이너를 클래스 주위로 전달하면 서비스 로케이터 패턴이 되고 종종 안티 패턴으로 보입니다.
컨테이너는 컴포지션 루트를 벗어나면 안 되며 모든 인스턴스는 컴포지션 루트에서 가져와야 합니다.

결론



C#에서 DI 컨테이너의 기본 사용법을 살펴보았습니다. 인스턴스 수명 주기 확인과 같은 DI 컨테이너 사용 방법에 대한 세부 정보는 다루지 않았습니다. 그러나 DI 컨테이너 자체를 이해하는 것이 좋은 출발점입니다.

좋은 웹페이지 즐겨찾기