C#/C# 교과서

[C# 교과서] 48~49. 제네릭 클래스 만들기, 확장 메서드 만들기

서니션 2023. 2. 6. 16:03
728x90
반응형

사용자 정의 클래스를 매개변수로 사용하는 제네릭 클래스

- 성능 향상을 가져다 주는 기법을 제네릭

- 매개변수화된 형식을 만드는 데 사용

- 제네릭에 전달하는 매개변수를 형식 매개변수라고 함


컬렉션 이니셜라이저로 제네릭 리스트 초기화

using System;

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

class Main2
{
    static void Main()
    {
        List<Person> people = new List<Person>
        {
            new Person { Name = "이재현"},
            new Person { Name = "이주연"},
            new Person { Name = "김영훈"}
        };

        foreach (var person in people)
        {
            Console.WriteLine(person.Name);
        }
    }
}

List<T> 형태의 컬렉션 개체를 선언과 동시에 특정 개체 값으로 초기화 가능

이러한 내용을 컬렉션 이니셜라이저라고 함


제네릭 클래스에 사용자 정의 클래스 사용하기

List<T> 형태의 T에 사용자 정의 클래스를 매개 변수로 사용 가능

이또한 컬렉션 개체를 생성할 때 바로 특정 요소로 초기화 가능

using System;

class Person
{
    public int Age { get; set; }
    public string Name { get; set; }
}

class Main2
{
    static void Main()
    {
        var people = new List<Person>()
        {
            new Person() { Age = 27, Name = "이재현"},
            new Person() { Age = 26, Name = "이주연"},
            new Person() { Age = 27, Name = "김영훈"}
        };

        foreach (var person in people)
        {
            Console.WriteLine($"{person.Name}은 {person.Age}살 입니다.");
        }
    }
}

제네릭 개체를 초기화하는 세 가지 방법 정리

1. List<T>에 List<Insolation> 형태로 사용자 정의 클래스를 넣고 개체 생성, 리스트를 선언과 동시에 초기화할 때 컬렉션 이니셜라이저를 사용하여 한 번에 데이터 여러개를 줄 수 있음

2. 이미 기본 값으로 초기화딘 리스트에 추가로 데이터를 입력할 때는 Add()메서드에 개체를 개체 이니셜라이저로 줄 수 있음

3. AddRange() 메서드로 데이터 리스트 여러 개를 한꺼번에 줄 수 있음

* 리스트 값을 출력할 때는 foreach문으로 반복해서 사용


List<T>의 T에 사용자 지정 클래스 설정

using System;

class AreaCode
{
    public string Number { get; set; }
    public string Areaname { get; set; }
}

class Main2
{
    static void Main()
    {
        List<AreaCode> areas = new List<AreaCode>();

        AreaCode seoul = new AreaCode(); // 속성으로 개체 초기화
        seoul.Number = "02";
        seoul.Areaname = "서울";

        AreaCode sejong = new AreaCode() // 개체 이니셜라이저로 개체 초기화
        {
            Number = "044",
            Areaname = "세종"
        };

        areas.Add(seoul);
        areas.Add(sejong);

        foreach (var area in areas)
        {
            Console.WriteLine($"번호 : {area.Number}, 지역 : {area.Areaname}");
        }
    }
}

세미콜론 주의하기!!


사전 제네릭 클래스 소개

리스트, List<T> 사전, Dictionary<Tkey, TValue>
요소 하나에 값을 저장 요소 하나에 키와 값을 저장
인덱스를 사용하여 요소에 접근 키를 사용하여 요소에 접근
요소 값 중복을 허용 요소 중복은 허용하나 키 중복은 허용하지 않음
반복이 빠름 특정 키에 검색이 빠름

 

  • Dictionary<Tkey, TValue> : 일반적인 형태로 저장하고, 정렬되지는 않음
  • SortedList<Tkey, TValue> : 키로 정렬하고, 정렬된 데이터를 빠르게 출력
  • SortedDictionary<Tkey, TValue> : 키로 정렬하고, 정렬되지 않은 데이터를 빠르게 출력

제네릭 인터페이스

  • ICollection<T> 인터페이스 : 제네릭 컬렉션 관련 클래스의 부모 역할을 하는 인터페이스 중 하나인 ICollection<T> 인터페이스는 제네릭 컬렉션을 조작하는 메서드 정의를 제공
    • Count : 요소 개수를 반환
    • Add(T) : T 개체를추가
    • Clear() : 항목을 모두 제거
    • Contains(T) : 특정 값이 들어 있는지 여부를 확인
    • Remove(T) : 맨 처음 발견되는 특정 개체를 제거
  • IEnumberable<T> 인터페이스 : 컬렉션의 데이터를 읽기 전용으로 출력할 때 사용. 당연하게 데이터를 수정할 때는 사용 불가능. 

문자열 배열을 사용하는 세 가지 방법

using System;

class Main2
{
    static void Main()
    {
        // 문자열 배열을 선언하는 기본적인 방법
        var a1 = new string[] { "Red", "Green", "Blue" };

        // List<T> 개체를 생성한 후 문자열 배열을 ToList() 메서드로 변환
        var a2 = new List<string>(); 
        a2 = a1.ToList();

        // IEnumerable<T> 개체를 생성한 후 문자열 배열을 바로 대입 가능
        IEnumerable<string> a3 = a1;

        // IEnumerable<T> 개체를 ToList() 메서드로 List<T> 형태로 변환
        var a4 = a3.ToList();

        // IEnumerable<T> 개체는 주로 foreach 문으로 반복 사용
        foreach (var arr in a3)
        {
            Console.WriteLine(arr);
        }

        // string[], List<T> 개체는 for문으로 반복 가능
        for (int i = 0; i < 3; i++)
        {
            Console.WriteLine($"{a1[i]},{a2[i]},{a4[i]}");
        }
    }
}

제네릭 클래스 만들기

using System;

// 클래스<T> 형태로 제네릭 클래스 만들기
public class Cup<T>
{
    public T Content {get; set;}
}
class Main2
{
    static void Main()
    {
        // T에 string을 전달하여 문자열을 저장하는 속성 생성
        Cup<string> text = new Cup<string>();
        text.Content = "문자열";

        // T에 int를 전달하여 정수형을 저장하는 속성 생성
        Cup<int> number = new Cup<int>();
        number.Content = 1234;

        Console.WriteLine($"{text.Content}, {number.Content}");
    }
}

제네릭에 사용자 정의 형식 클래스 전달하기

using System;

class Juice {}
class Coffee {}

// 클래스<T> 형태로 제네릭 클래스 만들기
public class Cup<T>
{
    public T Type {get; set;}
}
class Main2
{
    static void Main()
    {
        Cup<Juice> juice = new Cup<Juice>();
        juice.Type = new Juice();
        Console.WriteLine(juice.Type.ToString());

        var coffee = new Cup<Coffee> { Type = new Coffee() };
        Console.WriteLine(coffee.Type.ToString());
    }
}

출력결과 >

Juice
Coffee

설명 >

T 형식 매개변수로 전송하면 juice 개체의 Type 속성은 Juice 클래스의 인스턴스가 됨


제네릭 클래스와 제네릭 메서드

형식 매개변수 T는 클래스에 사용할 수 있으며 마찬가지로 필드, 속성, 메서드의 매개변수 형식 또는 반환형식에 사용할 수 있음


확장 메서드

  • 이미 만들어 있는 클래스 기능 확장
  • 클래스와 구조체, 인터페이스에서 사용 가능
  • 특히 봉인(sealed) 클래스는 상속이 불가능하므로 봉인 클래스에 새로운 메서드를 적용하기가 유용
  • static 키워드가 붙은 클래스에 static 메서드로 만들어짐
  • 반드시 동일한 네임스페이스를 참조해야 함
  • 확장 메서드의 첫 번째 매개변수에 this 키워드를 지정하여 확장 메서드를 사용할 개체 형식 선택
  • 확장 메서드를 사용하면 같은 네임스페이스의 모든 클래스에서 해당 확장 메서드 호출 가능, 확장 메서드는 이미 완성된 기존 형식에 새로운 메서드를 추가하는 방법으로 사용

> public static void MethodName(this object obj, int i) { }

> public static void MethodName(this string str, int i) { }

 

확장 메서드 만들기 정리

  1. 정적 클래스에 정적 메서드로 구현
  2. 첫 번째 메서드 매개변수에 this 키워드를 붙임
  3. 같은 범위(scope)를 같은 네임스페이스에서 호출 가능
  4. 확장 메서드도 오버로드가 가능

확장 메서드로 문자열 기능 확장하기

using System;

static class ExtensionFunction
{
    static string Three(this string value)
    {
        return value.Substring(0,3);
    }
    static void Main()
    {
        Console.WriteLine("안녕하세요".Three());
    }
}

확장 메서드로 기존 형식에 새로운 메서드 추가하기

using System;

namespace ExtensionMethodDemo
{
    public static class MyClass
    {
        public static int WordCount(this String str)
        {
            return str.Split(new char[] {' ','.','?'},
            StringSplitOptions.RemoveEmptyEntries).Length;
        }
    }
    class ExtensionMethodDemo
    {
        static void Main()
        {
            string s = "안녕하세요? 확장 메서드... ...";
            Console.WriteLine(s.Length); // 문자 개수
            Console.WriteLine(s.WordCount()); // 단어 개수
        }
    }
}

출력결과 >

20

3

 

문자열 변수 s에는 원래 WordCount() 라는 메서드가 없지만, 같은 네임스페이스에 정의된 MyClass의 WordCount() 확장 메서드를 s 변수에서 사용할 수 있게 함


확장 메서드를 사용하여 형식에 메서드 추가

다음 코드의 Original 클래스는 아무 멤버도 갖지 않은 클래스이지만, OriginalExtension 클래스에서 NewMethod()를 참조해서 새로운 메서드를 추가하여 사용할 수 있음

using System;

public class Original { }

public static class OriginalExtension
{
    public static void NewMethod(this Original original)
    => Console.WriteLine("새로운 메서드 추가");
}

class ExtensionMethodNote
{
    static void Main()
    {
        (new Original()).NewMethod(); // 확장 메서드 호출
    }
}

 

728x90
반응형