C\#의 의존 주입 과 IoC 용기 에 대한 자세 한 설명

본 논문 에서 우 리 는 C\#로 매우 간단 한 코드 예 시 를 재 구성 하여 주입 과 IoC 용기 에 의존 하 는 것 을 설명 할 것 이다. 
프로필:
주입 과 IoC 에 의존 하 는 것 은 언뜻 보기 에는 상당히 복잡 할 수 있 지만 쉽게 배우 고 이해 할 수 있다.
본 논문 에서 우 리 는 C\#에서 매우 간단 한 코드 예 시 를 재 구성 하여 주입 과 IoC 용기 에 의존 하 는 것 을 설명 할 것 이다.
요청:
사용 가능 한 제품 을 보고 이름 에 따라 제품 을 검색 할 수 있 는 프로그램 을 만 듭 니 다.
첫 번 째 시도:
우 리 는 층 구 조 를 만 드 는 것 부터 시작 할 것 이다.분 층 구 조 를 사용 하 는 것 은 여러 가지 장점 이 있 지만 우 리 는 본 논문 에서 그것들 을 열거 하지 않 을 것 이다.왜냐하면 우리 가 주목 하 는 것 은 주입 에 의존 하 는 것 이기 때문이다.

다음은 응용 프로그램의 클래스 입 니 다.

우선,우 리 는 Product 클래스 를 만 드 는 것 부터 시작 할 것 입 니 다.

public class Product
{
  public Guid Id { get; set; }
  public string Name { get; set; }
  public string Description { get; set; }
}
그리고 데이터 액세스 층 을 만 들 것 입 니 다:

public class ProductDAL
{
  private readonly List<Product> _products;

  public ProductDAL()
  {
    _products = new List<Product>
    {
      new Product { Id = Guid.NewGuid(), Name= "iPhone 9", 
             Description = "iPhone 9 mobile phone" },
      new Product { Id = Guid.NewGuid(), Name= "iPhone X", 
             Description = "iPhone X mobile phone" }
    };
  }

  public IEnumerable<Product> GetProducts()
  {
    return _products;
  }

  public IEnumerable<Product> GetProducts(string name)
  {
    return _products
      .Where(p => p.Name.Contains(name))
      .ToList();
  }
}
그리고 우 리 는 업무 층 을 만 들 것 입 니 다.

public class ProductBL
{
  private readonly ProductDAL _productDAL;

  public ProductBL()
  {
    _productDAL = new ProductDAL();
  }

  public IEnumerable<Product> GetProducts()
  {
    return _productDAL.GetProducts();
  }

  public IEnumerable<Product> GetProducts(string name)
  {
    return _productDAL.GetProducts(name);
  }
}
마지막 으로 UI 를 만 들 것 입 니 다:

class Program
{
  static void Main(string[] args)
  {
    ProductBL productBL = new ProductBL();

    var products = productBL.GetProducts();

    foreach (var product in products)
    {
      Console.WriteLine(product.Name);
    }

    Console.ReadKey();
  }
}
우리 가 처음 시도 한 코드 는 좋 은 작업 성과 라 고 썼 지만 몇 가지 문제 가 있다.
1.우 리 는 세 개의 서로 다른 팀 을 각 층 에서 일 하 게 해 서 는 안 된다.
2.업무 층 은 데이터 액세스 층 의 실현 에 의존 하기 때문에 확장 하기 어렵다.
3.업무 층 은 데이터 액세스 층 의 실현 에 의존 하기 때문에 유지 하기 어렵다.
4.소스 코드 는 테스트 하기 어렵다.
두 번 째 시도:
높 은 등급 의 대상 은 낮은 등급 의 대상 에 의존 해 서 는 안 된다.둘 다 추상 에 의존 해 야 한다.그렇다면 추상 적 인 개념 은 무엇 일 까?
추상 은 기능 의 정의 이다.우리 의 예 에서 업무 층 은 데이터 액세스 층 에 의존 하여 도 서 를 검색 한다.C\#에서 우 리 는 인 터 페 이 스 를 사용 하여 추상 을 실현 한다.인 터 페 이 스 는 기능 의 추상 을 나타 낸다.
추상 을 만들어 봅 시다.
다음은 데이터 액세스 층 의 추상 입 니 다.

public interface IProductDAL
{
  IEnumerable<Product> GetProducts();
  IEnumerable<Product> GetProducts(string name);
}
데이터 액세스 층 을 업데이트 해 야 합 니 다.

public class ProductDAL : IProductDAL
우 리 는 업무 층 을 갱신 해 야 한다.실제로 저 희 는 업무 층 을 업데이트 하여 데이터 액세스 층 의 추상 에 의존 하 게 할 것 입 니 다.데이터 액세스 층 의 실현 에 의존 하 는 것 이 아 닙 니 다.

public class ProductBL
{
  private readonly IProductDAL _productDAL;

  public ProductBL()
  {
    _productDAL = new ProductDAL();
  }

  public IEnumerable<Product> GetProducts()
  {
    return _productDAL.GetProducts();
  }

  public IEnumerable<Product> GetProducts(string name)
  {
    return _productDAL.GetProducts(name);
  }
}
우 리 는 또한 업무 층 의 추상 을 만들어 야 한다.

public interface IProductBL
{
  IEnumerable<Product> GetProducts();
  IEnumerable<Product> GetProducts(string name);
}
우리 도 업무 층 을 갱신 해 야 한다.

public class ProductBL : IProductBL
최종 적 으로 UI 를 업데이트 해 야 합 니 다:

class Program
{
  static void Main(string[] args)
  {
    IProductBL productBL = new ProductBL();

    var products = productBL.GetProducts();

    foreach (var product in products)
    {
      Console.WriteLine(product.Name);
    }

    Console.ReadKey();
  }
}
우리 가 두 번 째 시도 에서 한 코드 는 유효 하지만,우 리 는 여전히 데이터 액세스 층 의 구체 적 인 실현 에 의존한다.

public ProductBL()
{
  _productDAL = new ProductDAL();
}
그렇다면 어떻게 해결 할 것 인가?
주입 패턴 에 의존 해 역할 을 하 는 곳 이다.
최종 시도
지금까지 우리 가 한 일 은 주입 에 의존 하 는 것 과 무관 하 다.
높 은 등급 에 있 는 업무 층 을 낮은 등급 의 대상 에 의존 하 게 하기 위해 서 는 구체 적 으로 실현 되 지 않 고 다른 사람 이 클래스 를 만들어 야 한다.다른 사람들 은 반드시 밑바닥 대상 의 구체 적 인 실현 을 제공 해 야 한다.이것 이 바로 우리 가 말 한 의존 주입 이다.그것 은 우리 가 의존 대상 을 더 높 은 등급 의 대상 에 주입 한 다 는 뜻 이다.의존 항 주입 을 실현 하 는 방법 중 하 나 는 구조 함 수 를 사용 하여 의존 항 주입 을 하 는 것 이다.
업무 층 업데이트:

public class ProductBL : IProductBL
{
  private readonly IProductDAL _productDAL;

  public ProductBL(IProductDAL productDAL)
  {
    _productDAL = productDAL;
  }

  public IEnumerable<Product> GetProducts()
  {
    return _productDAL.GetProducts();
  }

  public IEnumerable<Product> GetProducts(string name)
  {
    return _productDAL.GetProducts(name);
  }
}
인 프 라 시설 은 반드시 실현 에 대한 의존 을 제공 해 야 한다.

class Program
{
  static void Main(string[] args)
  {
    IProductBL productBL = new ProductBL(new ProductDAL());

    var products = productBL.GetProducts();

    foreach (var product in products)
    {
      Console.WriteLine(product.Name);
    }

    Console.ReadKey();
  }
}
데이터 액세스 층 을 만 드 는 제어 와 인 프 라 를 결합 합 니 다.반전 을 통제 하 는 것 이 라 고도 한다.우 리 는 업무 층 에서 데이터 액세스 층 을 만 드 는 실례 가 아니 라 인 프 라 시설 에서 만 듭 니 다. Main 방법 은 인 스 턴 스 를 업무 논리 층 에 주입 합 니 다.따라서 우 리 는 저층 대상 의 실례 를 고위 층 대상 의 실례 에 주입 한다.
의존 주입 이 라 고 합 니 다.
지금 우리 가 코드 를 보면 우 리 는 업무 액세스 층 에서 데이터 액세스 층 의 추상 에 만 의존 하고 업무 액세스 층 은 데이터 액세스 층 이 실현 하 는 인 터 페 이 스 를 사용한다.따라서 우 리 는 더욱 높 은 차원 의 대상 과 더 낮은 차원 의 대상 이 모두 추상 적 인 원칙 에 의존 하고 추상 은 더욱 높 은 차원 의 대상 과 더 낮은 차원 의 대상 간 의 계약 이다.
이제 우 리 는 서로 다른 팀 을 서로 다른 층 에서 일 하 게 할 수 있다.우 리 는 한 팀 이 데이터 액세스 층 을 처리 하고 한 팀 이 업무 층 을 처리 하 며 한 팀 이 UI 를 처리 하도록 할 수 있다.
다음은 유지 가능성 과 확장 가능 한 장점 을 보 여 줍 니 다.예 를 들 어 SQL Server 에 새로운 데이터 액세스 층 을 만 들 려 면 데이터 액세스 층 의 추상 화 를 실현 하고 인 프 라 에 인 스 턴 스 를 주입 해 야 합 니 다.
마지막 으로 소스 코드 는 이제 테스트 할 수 있 습 니 다.우 리 는 어느 곳 에서 든 인 터 페 이 스 를 사용 하기 때문에 비교적 낮은 단원 테스트 에서 다른 실현 을 쉽게 제공 할 수 있다.낮은 테스트 가 쉽게 설 치 될 것 이라는 뜻 이다.
이제 업무 층 을 테스트 합 시다.
저 희 는 xUnit 을 사용 하여 유닛 테스트 를 하고 Moq 아 날로 그 데이터 액세스 층 을 사용 할 것 입 니 다.
다음은 업무 층 의 유닛 테스트 입 니 다.

public class ProductBLTest
{
  private readonly List<Product> _products = new List<Product>
  {
    new Product { Id = Guid.NewGuid(), Name= "iPhone 9", 
           Description = "iPhone 9 mobile phone" },
    new Product { Id = Guid.NewGuid(), Name= "iPhone X", 
           Description = "iPhone X mobile phone" }
  };
  private readonly ProductBL _productBL;

  public ProductBLTest()
  {
    var mockProductDAL = new Mock<IProductDAL>();
    mockProductDAL
      .Setup(dal => dal.GetProducts())
      .Returns(_products);
    mockProductDAL
      .Setup(dal => dal.GetProducts(It.IsAny<string>()))
      .Returns<string>(name => _products.Where(p => p.Name.Contains(name)).ToList());

    _productBL = new ProductBL(mockProductDAL.Object);
  }

  [Fact]
  public void GetProductsTest()
  {
    var products = _productBL.GetProducts();
    Assert.Equal(2, products.Count());
  }

  [Fact]
  public void SearchProductsTest()
  {
    var products = _productBL.GetProducts("X");
    Assert.Single(products);
  }
}
의존 항 주입 을 사용 하면 유닛 테스트 를 쉽게 설정 할 수 있 음 을 볼 수 있 습 니 다.
IoC 용기
용 기 는 주입 에 의존 하 는 것 을 실현 하 는 데 도움 을 줄 뿐이다.용 기 는 보통 세 가지 서로 다른 기능 을 실현 한다.
1.등록 인터페이스 와 구체 적 인 실현 사이 의 맵
2.대상 을 만 들 고 의존 관 계 를 분석
3.석방
맵 을 등록 하고 대상 을 만 드 는 간단 한 용 기 를 실현 합 니 다.
우선,우 리 는 매 핑 된 데이터 구 조 를 저장 해 야 한다.우 리 는 Hashtable 을 선택 할 것 이다.이 데이터 구 조 는 매 핑 을 저장 할 것 이다.
우선,우 리 는 용기 의 구조 함수 에서 Hashtable 을 초기 화 할 것 입 니 다.그리고 나 서,우 리 는 등록 맵 을 등록 하기 위해 RegisterTransient 방법 을 만 들 것 이다.마지막 으로 대상 을 만 드 는 방법 을 만 들 것 입 니 다. Create :

public class Container
{
  private readonly Hashtable _registrations;

  public Container()
  {
    _registrations = new Hashtable();
  }

  public void RegisterTransient<TInterface, TImplementation>()
  {
    _registrations.Add(typeof(TInterface), typeof(TImplementation));
  }

  public TInterface Create<TInterface>()
  {
    var typeOfImpl = (Type)_registrations[typeof(TInterface)];
    if (typeOfImpl == null)
    {
      throw new ApplicationException($"Failed to resolve {typeof(TInterface).Name}");
    }
    return (TInterface)Activator.CreateInstance(typeOfImpl);
  }
}
최종 적 으로 UI 를 업데이트 합 니 다.

class Program
{
  static void Main(string[] args)
  {
    var container = new Container();
    container.RegisterTransient<IProductDAL, ProductDAL>();

    IProductBL productBL = new ProductBL(container.Create<IProductDAL>());
    var products = productBL.GetProducts();

    foreach (var product in products)
    {
      Console.WriteLine(product.Name);
    }

    Console.ReadKey();
  }
}
이제 용기 에서 Resolve 방법 을 실현 합 니 다.이 방법 은 의존 관 계 를 해결 할 것 이다.
Resolve 방법 은 다음 과 같 습 니 다.

public T Resolve<T>()
{
    var ctor = ((Type)_registrations[typeof(T)]).GetConstructors()[0];
    var dep = ctor.GetParameters()[0].ParameterType;
    var mi = typeof(Container).GetMethod("Create");
    var gm = mi.MakeGenericMethod(dep);
    return (T)ctor.Invoke(new object[] { gm.Invoke(this, null) });
}
그리고 우 리 는 UI 에서 다음 과 같은 Resolve 방법 을 사용 할 수 있 습 니 다.

class Program
{
    static void Main(string[] args)
    {
        var container = new Container();
        container.RegisterTransient<IProductDAL, ProductDAL>();
        container.RegisterTransient<IProductBL, ProductBL>();

        var productBL = container.Resolve<IProductBL>();
        var products = productBL.GetProducts();

        foreach (var product in products)
        {
            Console.WriteLine(product.Name);
        }

        Console.ReadKey();
    }
}
위의 소스 코드 에서 용 기 는 container.Resolve()방법 으로 ProductBL 류 의 대상 을 만 듭 니 다.ProductBL 류 는 IProductDAL 의 의존 항 이다.따라서 container.Resolve() ProductDAL 대상 을 자동 으로 만 들 고 주입 하여 ProductBL 클래스 의 대상 을 되 돌려 줍 니 다.이 모든 것 은 막후 에서 진행 된다.ProductDAL 대상 을 만 들 고 주입 하 는 것 은 우리 가 IProductDAL 로 ProductDAL 형식 을 등 록 했 기 때문이다.
이것 은 당신 에 게 IoC 용기 뒤의 내용 을 보 여 주 는 매우 간단 하고 기본 적 인 IoC 용기 입 니 다.그렇습니다.나 는 네가 이 문장 을 즐겨 읽 기 를 바란다.
이상 은 C\#의 의존 주입 과 IoC 용기 에 대한 상세 한 내용 입 니 다.C\#의존 주입 과 IoC 용기 에 대한 자 료 는 다른 관련 글 을 주목 하 십시오!

좋은 웹페이지 즐겨찾기