본문 바로가기

웹 개발/ASP .NET

[ASP.NET MVC5] 확장 메서드

확장 메서드로 클래스 기능 확장하기


확장 메서드는 직접 변경할 수 없는 클래스에 새로운 메서드를 추가할 수 있는 편리한 방법이다.
이번 포스팅에서는 확장 메서드를 이용해 타사에서 제공받은 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));

        }

 

 

확장 메서드와 인터페이스의 장점


  1. 다형성 지원:
    IEnumerable<Product>를 구현한 모든 클래스에서 동일한 확장 메서드를 사용할 수 있다.
  2. 재사용성:
    특정 클래스가 아닌 인터페이스를 대상으로 메서드를 작성했기 때문에 더 많은 클래스에 적용 가능하다.
  3. 코드 간결화:
    인터페이스에 기능을 추가하면서도 기존 코드를 변경하지 않아도 된다.

 

정리


확장 메서드는 인터페이스를 확장하여 더욱 강력한 다형성을 제공한다.
이번 예제에서는 IEnumerable<Product>를 대상으로 확장 메서드를 정의해, ShoppingCart뿐 아니라 모든 IEnumerable<Product>에서 동일한 메서드를 사용할 수 있었다.

핵심 포인트

  • 확장 메서드는 특정 클래스뿐 아니라 인터페이스에도 적용할 수 있다.
  • 인터페이스 확장은 재사용성과 다형성을 극대화한다.