특수한 개념으로부터 공통된 개념을 찾아 묶는 것
ex) 포유류 - 사람, 돼지, 오리너구리, 고래
데이터 형식을 일반화한 메소드
메소드 이름 뒤와 실제 형식 자리에 형식 매개 변수(Type Parameter) 입력
<>
사이에 일반화 데이터 형식 입력 (→ 형식 매개 변수임을 알려줌)한정자 반환형식 메소드이름 <형식매개변수> (매개변수목록)
{
//....
}
// int버전
void CopyArray(int[] source, int[] target)
{
for (int i = 0; i < source.Length; i++)
target[i] = source[i];
}
// string버전
void CopyArray(string[] source, string[] target)
{
for (int i = 0; i < source.Length; i++)
target[i] = source[i];
}
// 일반화
void CopyArray<T>(T[] source, T[] target)
{
for (int i = 0; i < source.Length; i++)
target[i] = source[i];
}
예제
using System;
namespace CopyingArray
{
class MainApp
{
// 일반화 메소드 선언
static void CopyArray<T>(T[] source, T[] target)
{
for (int i = 0; i < source.Length; i++)
target[i] = source[i];
}
static void Main(string[] args)
{
int[] source = { 1, 2, 3, 4, 5 };
int[] target = new int[source.Length];
// 형식매개변수 T에 int 대입해 호출 (컴파일 단계에서 int로 치환)
CopyArray<int>(source, target);
foreach (int element in target)
Console.WriteLine(element);
string[] source2 = { "하나", "둘", "셋", "넷", "다섯" };
string[] target2 = new string[source2.Length];
// 형식매개변수 T에 string 대입해 호출 (컴파일 단계에서 string로 치환)
CopyArray<string>(source2, target2);
foreach (string element in target2)
Console.WriteLine(element);
}
}
}
class 클래스이름<형식매개변수>
{
//...
}
// 기능이 같은 클래스1
class Array_Int
{
private int[] array;
//...
public int GetElement( int index ) { return array[index];}
}
// 기능이 같은 클래스2
class Array_Double
{
private double[] array;
//...
public double GetElement( int index ) { return array[index];}
}
// 일반화 클래스
class Array_Generic<T>
{
private T[] array;
//...
public T GetElement( int index ) { return array[index];}
}
// 일반화 클래스 사용
Array_Generic<int> intArr = new Array_Generic<int>();
Array_Generic<double> dblArr = new Array_Generic<double>();
// 매개변수 T는 객체 생성 시 입력받은 형식으로 치환되어 다음과 같이 컴파일됨
// int형식으로 사용될 때
class Array_Generic
{
private int[] array;
//...
public int GetElement( int index ) { return array[index];}
}
// double 형식으로 사용될 때
class Array_Generic
{
private double[] array;
//...
public double GetElement( int index ) { return array[index];}
}
예제
using System;
namespace Generic
{
class MyList<T> // 형식 매개변수 T 추가
{
private T[] array;
public MyList()
{
array = new T[3]; // 배열 길이 = 3
}
// 인덱서
public T this[int index]
{
get
{
return array[index];
}
set
{
// 배열 길이 작으면 재조정, 늘리기 + 값 부여
if (index >= array.Length)
{
Array.Resize<T>(ref array, index + 1);
Console.WriteLine($"Array Resized : {array.Length}");
}
array[index] = value;
}
}
// array길이
public int Length
{
get { return array.Length; }
}
}
class MainApp
{
static void Main(string[] args)
{
MyList<string> str_list = new MyList<string>();
str_list[0] = "abc";
str_list[1] = "def";
str_list[2] = "ghi";
str_list[3] = "jkl";
str_list[4] = "mno";
for (int i = 0; i < str_list.Length; i++)
Console.WriteLine(str_list[i]);
Console.WriteLine();
MyList<int> int_list = new MyList<int>();
int_list[0] = 0;
int_list[1] = 1;
int_list[2] = 2;
int_list[3] = 3;
int_list[4] = 4;
for (int i = 0; i < int_list.Length; i++)
Console.WriteLine(int_list[i]);
}
}
}
where 형식매개변수 : 제약조건
예제
using System;
namespace ConstraintsOnTypeParameters
{
class StructArray<T> where T : struct // T = 값 형식
{
public T[] Array { get; set; }
public StructArray(int size)
{
Array = new T[size];
}
}
class RefArray<T> where T : class // T = 참조 형식
{
public T[] Array { get; set; }
public RefArray(int size)
{
Array = new T[size];
}
}
class Base { }
class Derived : Base { }
class BaseArray<U> where U : Base // 명시한 기반 클래스의 파생 클래스여야 함
{
public U[] Array { get; set; }
public BaseArray(int size)
{
Array = new U[size];
}
public void CopyyArray<T>(T[] Target) where T : U // T는 또 다른 형식 매개변수 U로부터 상속받은 클래스여야 함
{
Target.CopyTo(Array, 0);
}
}
class MainApp
{
public static T CreateInstance<T>() where T : new()
{
return new T();
}
static void Main(string[] args)
{
StructArray<int> a = new StructArray<int>(3);
a.Array[0] = 0;
a.Array[1] = 1;
a.Array[2] = 2;
Console.WriteLine("a");
for (int i = 0; i < a.Array.Length; i++)
Console.WriteLine(a.Array[i]);
RefArray<StructArray<double>> b = new RefArray<StructArray<double>>(3);
b.Array[0] = new StructArray<double>(5);
b.Array[1] = new StructArray<double>(10);
b.Array[2] = new StructArray<double>(1005);
Console.WriteLine("b");
for (int i = 0; i < b.Array.Length; i++)
for (int j = 0; j < b.Array[i].Array.Length; j++)
Console.WriteLine(b.Array[i]);
BaseArray<Base> c = new BaseArray<Base>(3);
c.Array[0] = new Base();
c.Array[1] = new Derived();
c.Array[2] = CreateInstance<Base>();
Console.WriteLine("c");
for (int i = 0; i < c.Array.Length; i++)
Console.WriteLine(c.Array[i]);
BaseArray<Derived> d = new BaseArray<Derived>(3);
d.Array[0] = new Derived(); // Base 형식은 여기에 할당 할 수 없다.
d.Array[1] = CreateInstance<Derived>();
d.Array[2] = CreateInstance<Derived>();
Console.WriteLine("d");
for (int i = 0; i < d.Array.Length; i++)
Console.WriteLine(d.Array[i]);
BaseArray<Derived> e = new BaseArray<Derived>(3);
e.CopyyArray<Derived>(d.Array);
Console.WriteLine("e");
for (int i = 0; i < e.Array.Length; i++)
Console.WriteLine(e);
}
}
}
object 형식
기반으로 요소에 접근할 때마다 박싱/언박싱
이 일어나 성능이 저하되는 문제 발생using System;
using System.Collections.Generic;
namespace UsingGenericList
{
class MainApp
{
static void Main(string[] args)
{
List<int> list = new List<int>(); # 인스턴트 생성 시 형식 매개변수 작성
for (int i = 0; i < 5; i++)
list.Add(i);
foreach (int element in list)
Console.Write($"{element} ");
Console.WriteLine();
list.RemoveAt(2);
foreach (int element in list)
Console.Write($"{element} ");
Console.WriteLine();
list.Insert(2, 2);
foreach (int element in list)
Console.Write($"{element} ");
Console.WriteLine();
}
}
}
using System;
using System.Collections.Generic;
namespace UsingGenericQueue
{
class MainApp
{
static void Main(string[] args)
{
Queue<int> queue = new Queue<int>(); # 인스턴트 생성 시 형식 매개변수 작성
queue.Enqueue(1);
queue.Enqueue(2);
queue.Enqueue(3);
queue.Enqueue(4);
queue.Enqueue(5);
while (queue.Count > 0)
Console.WriteLine(queue.Dequeue());
}
}
}
using System;
using System.Collections.Generic;
namespace UsingGenericStack
{
class MainApp
{
static void Main(string[] args)
{
Stack<int> stack = new Stack<int>();
stack.Push(1);
stack.Push(2);
stack.Push(3);
stack.Push(4);
stack.Push(5);
while (stack.Count > 0)
Console.WriteLine(stack.Pop());
}
}
}
using System;
using System.Collections.Generic;
namespace UsingDictionary
{
class MainApp
{
static void Main(string[] args)
{
Dictionary<string, string> dic = new Dictionary<string, string>();
dic["하나"] = "one";
dic["둘"] = "two";
dic["셋"] = "three";
dic["넷"] = "four";
dic["다섯"] = "five";
Console.WriteLine(dic["하나"]);
Console.WriteLine(dic["둘"]);
Console.WriteLine(dic["셋"]);
Console.WriteLine(dic["넷"]);
Console.WriteLine(dic["다섯"]);
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
namespace EnumerableGeneric
{
class MyList<T> : IEnumerable<T>, IEnumerator<T> # 상속
{
private T[] array;
int position = -1;
public MyList()
{
array = new T[3];
}
public T this[int index]
{
get
{
return array[index];
}
set
{
if (index >= array.Length)
{
Array.Resize<T>(ref array, index + 1);
Console.WriteLine($"Array Resized : {array.Length}");
}
array[index] = value;
}
}
public int Length
{
get { return array.Length; }
}
public IEnumerator<T> GetEnumerator()
{
return this;
}
IEnumerator IEnumerable.GetEnumerator()
{
return this;
}
public T Current
{
get { return array[position]; }
}
object IEnumerator.Current
{
get { return array[position]; }
}
public bool MoveNext()
{
if (position == array.Length - 1)
{
Reset();
return false;
}
position++;
return (position < array.Length);
}
public void Reset()
{
position = -1; ;
}
public void Dispose()
{
}
}
class MainApp
{
static void Main(string[] args)
{
MyList<string> str_list = new MyList<string>();
str_list[0] = "abc";
str_list[1] = "def";
str_list[2] = "ghi";
str_list[3] = "jkl";
str_list[4] = "mno";
foreach( string str in str_list)
Console.WriteLine( str );
Console.WriteLine();
MyList<int> int_list = new MyList<int>();
int_list[0] = 0;
int_list[1] = 1;
int_list[2] = 2;
int_list[3] = 3;
int_list[4] = 4;
foreach ( int no in int_list)
Console.WriteLine(no);
}
}
}
Queue queue = new Queue();
queue.Enqueue(10);
queue.Enqueue("한글");
queue.Enqueue(3.14);
Queue<int> queue2 = new Queue();
queue.Enqueue(10);
queue.Enqueue("한글");
queue.Enqueue(3.14);
=> Queue는 object형식으로 어떤 데이터 형식이 들어가도 상관없지만 박싱과 언박싱이 주기적으로 일어나 성능 문제를 가지고 있다.
Dictionary</* ⓐ */> dic = new Dictionary</* ⓐ */>();
dic["하나"] = "one";
dic["둘"] = "two";
dic["셋"] = "three";
dic["넷"] = "four";
dic["다섯"] = "five";
Console.WriteLine(dic["하나"]);
Console.WriteLine(dic["둘"]);
Console.WriteLine(dic["셋"]);
Console.WriteLine(dic["넷"]);
Console.WriteLine(dic["다섯"]);
=> string, string
1번에서 괄호 안에 있는 int 이부분도 잘못된 거 아닌가요?