확장 메서드로 클래스 기능 확장하기
확장 메서드는 직접 변경할 수 없는 클래스에 새로운 메서드를 추가할 수 있는 편리한 방법이다.
이번 포스팅에서는 확장 메서드를 이용해 타사에서 제공받은 Product 객체의 총합을 구하는 기능을 ShoppingCart 클래스에 추가하는 방법을 알아본다.
문제 상황
- Product 객체는 타사로부터 제공받은 클래스여서 소스 코드를 직접 수정할 수 없다.
- ShoppingCart 클래스에 담긴 Product 객체들의 **총 가격(Total Price)**을 구해야 한다.
이 경우 확장 메서드를 활용하면 간단하게 문제를 해결할 수 있다.
ShoppingCart 클래스 생성
먼저, Product 객체를 리스트로 담는 ShoppingCart 클래스를 생성한다.
ShoppingCart.cs
using System.Collections.Generic;
namespace LanguageFeatures.Models
{
public class ShoppingCart
{
public List<Product> Products { get; set; }
}
}
확장 메서드 정의
ShoppingCart 클래스에 총합 계산 기능을 추가하기 위해 확장 메서드를 작성한다.
MyExtensionMethod.cs
using System.Collections.Generic;
namespace LanguageFeatures.Models
{
public static class MyExtensionMethod
{
public static decimal TotalPrices(this ShoppingCart cartParam)
{
decimal total = 0;
foreach (Product prod in cartParam.Products)
{
total += prod.Price;
}
return total;
}
}
}
컨트롤러에서 확장 메서드 사용
확장 메서드는 실제 클래스의 메서드처럼 호출할 수 있다.
using System.Web.Mvc;
using LanguageFeatures.Models;
using System.Collections.Generic;
namespace LanguageFeatures.Controllers
{
public class HomeController : Controller
{
public ViewResult UseExtension()
{
ShoppingCart cart = new ShoppingCart
{
Products = new List<Product>
{
new Product { Name = "Kayak", Price = 275M },
new Product { Name = "Lifejacket", Price = 48.95M },
new Product { Name = "Soccer ball", Price = 19.50M },
new Product { Name = "Corner flag", Price = 34.95M }
}
};
decimal cartTotal = cart.TotalPrices();
return View("Result", (object)string.Format("Total: {0:c}", cartTotal));
}
}
}
확장 메서드로 인터페이스 활용하기
확장 메서드는 단순히 클래스뿐만 아니라 인터페이스에도 적용할 수 있다. 이를 통해 인터페이스를 구현하는 모든 클래스에서 동일한 확장 메서드를 활용할 수 있다. 이번에는 IEnumerable<T> 인터페이스를 구현한 클래스에 확장 메서드를 적용하는 방법을 살펴본다.
ShoppingCart 클래스에 IEnumerable<Product> 구현
ShoppingCart 클래스는 IEnumerable<Product>를 구현하여, 내부의 Products 리스트를 열거할 수 있도록 수정한다.
ShoppingCart.cs
using System.Collections;
using System.Collections.Generic;
namespace LanguageFeatures.Models
{
public class ShoppingCart : IEnumerable<Product>
{
public List<Product> Products { get; set; }
// IEnumerable<Product> 구현
public IEnumerator<Product> GetEnumerator()
{
return Products.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
- Products 리스트에 저장된 각 Product를 열거할 수 있도록 GetEnumerator 메서드를 구현했다.
- 이를 통해 ShoppingCart는 foreach 루프에서 사용할 수 있다.
인터페이스 확장 메서드 정의
이제 IEnumerable<Product>를 대상으로 확장 메서드를 정의한다.
MyExtensionMethod.cs
using System.Collections.Generic;
namespace LanguageFeatures.Models
{
public static class MyExtensionMethod
{
public static decimal TotalPrices(this IEnumerable<Product> productEnum)
{
decimal total = 0;
foreach (Product prod in productEnum)
{
total += prod.Price;
}
return total;
}
}
}
- this IEnumerable<Product> productEnum을 첫 번째 매개변수로 지정해 인터페이스를 확장한다.
- 이제 ShoppingCart뿐 아니라 IEnumerable<Product>를 구현하는 모든 클래스에서 이 확장 메서드를 사용할 수 있다.
컨트롤러에서 확장 메서드 사용
컨트롤러에서 확장 메서드를 호출하면, ShoppingCart 클래스뿐만 아니라 모든 IEnumerable<Product>에서 작동한다.
public ViewResult UseExtensionEnumerable() {
IEnumerable<Product> products = new ShoppingCart
{
Products = new List<Product> {
new Product { Name = "kayak", Price = 275M},
new Product { Name = "Lifejacket", Price = 48.95M},
new Product { Name = "Soccer ball", Price = 19.50M},
new Product { Name = "Corner flag", Price = 34.95M},
}
};
Product[] productArray = {
new Product { Name = "kayak", Price = 275M},
new Product { Name = "Lifejacket", Price = 48.95M},
new Product { Name = "Soccer ball", Price = 19.50M},
new Product { Name = "Corner flag", Price = 34.95M},
};
decimal cartTotal = products.TotalPrices();
decimal arrayTotal = productArray.TotalPrices();
return View("Result",
(object)String.Format("Cart Total: {0}, Array Total: {1}", cartTotal, arrayTotal));
}
확장 메서드와 인터페이스의 장점
- 다형성 지원:
IEnumerable<Product>를 구현한 모든 클래스에서 동일한 확장 메서드를 사용할 수 있다. - 재사용성:
특정 클래스가 아닌 인터페이스를 대상으로 메서드를 작성했기 때문에 더 많은 클래스에 적용 가능하다. - 코드 간결화:
인터페이스에 기능을 추가하면서도 기존 코드를 변경하지 않아도 된다.
정리
확장 메서드는 인터페이스를 확장하여 더욱 강력한 다형성을 제공한다.
이번 예제에서는 IEnumerable<Product>를 대상으로 확장 메서드를 정의해, ShoppingCart뿐 아니라 모든 IEnumerable<Product>에서 동일한 메서드를 사용할 수 있었다.
핵심 포인트
- 확장 메서드는 특정 클래스뿐 아니라 인터페이스에도 적용할 수 있다.
- 인터페이스 확장은 재사용성과 다형성을 극대화한다.
'웹 개발 > ASP .NET' 카테고리의 다른 글
[ASP.NET MVC5] Ninject로 의존성 주입(DI) 구현하기 (0) | 2024.11.26 |
---|---|
[ASP.NET MVC5] 람다식을 활용한 필터링과 간결한 코드 작성 (1) | 2024.11.26 |
[ASP.NET MVC5] 자동 구현 속성 (0) | 2024.11.25 |
[ASP.NET MVC5] MVC 패턴과 샘플 프로젝트 (0) | 2024.11.25 |
[ASP.NET MVC5] 동적 출력 (0) | 2024.11.25 |