제네릭 컬렉션의 사용법
 
제네릭 컬렉션(=제네릭의 기능을 사용하고 있는 컬렉션 클래스)의 사용법은 어려운 것이 없다.
 
기본적인 사용법만 얘기한다면, 다음의 원칙을 기억하면 좋다.
 
★ 제네릭 컬렉션의 형명의 뒤에 취급하는 데이터의 형명을 < > 로 둘러싸서 기술한다( 복수의 데이터형을 취급하는 경우에는 콤마로 구분한다)
 
즉, List<string>
 
과같이 사용하면 된다. new ArrayList() 와 같이 사용하듯, new List<string>() 과 같이 사용하면 된다.
 
Dictionary 클래스와 같이, 키(key)와 값(value)의 2개의 형태를 이용하는 클래스의 경우는, < > 안에 형태를 2개 지정한다.키가 정수이고 값이 문자열이라면,
 
Dictionary<int, string>
 
과 같이 사용한다. 그리고, 기존의 컬렉션과 취급방식은 큰 차이가 없다.
다음은 이러한 클래스의 사용예이다.
 
using System;
using System.Collections.Generic;
 
class Program
{
 static void Main(string[] args)
 {
    // 문자열을요소로서취급한다List 클래스
    List<string> list = new List<string>();
    list.Add("Sample List");
 
    Console.WriteLine(list[0]); // 출력:Sample List
 
    // 키가정수로값이문자열의요소를취급한다Dictionary 클래스
    Dictionary<int, string> dic = new Dictionary<int, string>();
    dic[0] = "Sample Dictionary";
 
    Console.WriteLine(dic[0]); // 출력:Sample Dictionary
 }
}
리스트4 List 클래스와 Dictionary 클래스의 사용예
 
물론, < > 로 둘러싸 지정한 형은, 그것을 상속한 형 또한 받아 들인다. 인터페이스를 지정했을 경우는, 그 인터페이스를 상속한 형 또한 받아 들인다.
 
using System;
using System.Collections.Generic;
 
// 인터페이스의정의
public interface ISample
{
 void SayISample();
}
 
// 추상클래스의정의
public abstract class SampleBase
{
 public abstract void SaySample();
}
 
// SampleBase 클래스를계승해,ISample 인터페이스를실장한클래스
public class Sample : SampleBase, ISample
{
 public override void SaySample()
 {
    Console.WriteLine("Sample!");
 }
 public void SayISample()
 {
    Console.WriteLine("ISample!");
 }
}
 
class Program
{
 static void Main(string[] args)
 {
    // SampleBase 형태의콜렉션에Sample 오브젝트를추가
    List<SampleBase> list1 = new List<SampleBase>();
    list1.Add(new Sample());
 
    list1[0].SaySample(); // 출력:Sample!
 
    // ISample 형태의콜렉션에Sample 오브젝트를추가
    List<ISample> list2 = new List<ISample>();
    list2.Add(new Sample());
 
    list2[0].SayISample(); // 출력:ISample!
 }
}
 
리스트5 상속과 인터페이스를 사용한 예
 
제네릭 메서드와 형 추론
 
제네릭은 클래스 이외에도 사용할 수 있다. 구조체나 인터페이스에도 사용할 뿐만 아니라, Delegate 나 메서드에도 사용할 수 있다.
 
여기에서는, 특히 제네릭을 사용한 메서드인 [제네릭 메서드]에 주목하자. 이것은, 바로 사용할 수 있는 편리한 기능이 있지만, 주의를 필요로 하는 부분도 있기 때문이다.
 
클래스 라이브러리가 제공하는 제네릭 메서드중에서, 특히 빈번히 사용한 수 있는, 배열을 소트하는 Array 클래스의 Sort 메서드일 것이다. 사용법은 클래스와 같이 메서드의 이름뒤에 < > 로 둘러싸 형명을 쓰면 된다.
 
using System;
using System.Collections.Generic;
 
class Program
{
 static void Main(string[] args)
 {
    int[] array = { 3, 2, 1 };
    Array.Sort<int>(array); // 제네릭·메소드의호출
 
    foreach (int i in array) Console.WriteLine(i);
    // 출력:
    // 1
    // 2
    // 3
 }
}
리스트6 제네릭 메서드의 사용예
 
<int>를 지정한 Sort<int> 메서드는 인수의 int 형태의 배열을 받아, 그 요소를 정렬하기 위한 메서드다.
 
그러나, Array.Sort 의 뒤엔 <int> 가 있다. 여기엔 큰 의미가 없다. 왜냐하면, 인수로 지정한 배열 변수(array)의 형이 int[] 이기 때문에, 통상 <int> 를 기술하는 것은 의미가 없기 때문이다.
 
여기에서, [형 추론] 이라고 하는 기능을 사용해 C# 컴파일러에 형 추리를 시킬 수 있다. 이 기능이 사용하기 위해 <int> 를 생략해도 의도대로 동작한다.
 
using System;
 
class Program
{
 static void Main(string[] args)
 {
    int[] array = { 3, 2, 1 };
    Array.Sort(array); // <int> ()를생략하고있다
 
    foreach (int i in array) Console.WriteLine(i);
    // 출력:
    // 1
    // 2
    // 3
 }
}
리스트7 형 추론에 의해 제네릭 메서드를 사용한 예
 
이 코드는 언뜻, 기존 C# 1.x 의 Sort 메서드의 호출과 구별이 되지 않는다.
 
그러나, ildasm 이나 .NET Reflector 에 의해 생성된 코드를 보면, 제네릭이 아닌 기존의 Sort 메서드가 아니고, 형 추론을 해 Sort<int> 메서드가 호출되는 것을 알 수 있다.
 
그런데, 형 추론은 강력하기는 하지만, 보기 드물게 형 추론을 사용 할 수 없는 경우도 있다.
 
예를 들면, IComparable 인테페이스를 구현한 base class 와 상속 클래스가 있는 경우, 그것을 명시적으로 구분하여 사용하지 않으면 결과가 바뀌어 버리는 일이 있다. 아래의 예를 보자.
 
using System;
 
public class ClassA : IComparable<ClassA>
{
 public int Value;
 public ClassA(int v)
 {
    Value = v;
 }
 
 public int CompareTo(ClassA other)
 {
    return Value.CompareTo(other.Value);
 }
}
 
public class ClassB : ClassA, IComparable<ClassB>
{
 public ClassB(int v) : base (v) { }
 
 public int CompareTo(ClassB other)
 {
    return other.Value.CompareTo(Value);
 }
}
 
class Program
{
 static void Main(string[] args)
 {
    ClassB[] array = {
      new ClassB(3),
      new ClassB(2),
      new ClassB(1),
    };
 
    Array.Sort<ClassA>(array);
    foreach (ClassB b in array) Console.WriteLine(b.Value);
    // 출력:
    // 1
    // 2
    // 3
 
    Array.Sort<ClassB>(array);
   foreach (ClassB b in array) Console.WriteLine(b.Value);
    // 출력:
    // 3
    // 2
    // 1
 }
}
 
리스트8 형 추론을 사용할 수 없는 예
 
이 예제에 대해, 형 지정을 생략해 Array.Sort(array); 라고 기술하면, Array.Sort<ClassB>(array)라고 추론되지만, 그 실행 결과는 Array.Sort<ClassA>(Array); 가 실행된다.
 

Posted by 땡초 POWERUMC
TAG ,

댓글을 달아 주세요