[ 학습 흐름 ]
[ 학습 흐름 ]
- 일반화 프로그래밍
- 일반화 메소드
- 일반화 클래스
- 형식 매개변수 제약시키기
- 일반화 컬렉션
- foreach를 사용할 수 있는 일반화 클래스
[ 일반화 프로그래밍 ]
[ 일반화 ]
- 특수한 개념으로 공통된 개념을 찾아 묶는것을 일반화라고 한다 ex) 포유류
- 일반화 프로그래밍은 일반화 하는 대상이 데이터 형식이다 .
- 매개변수의 형식만 다를 뿐, 내부 논리는 똑같은 코드를 일반화 할 수 있다면 여러 버전의 오버로딩이 필요 없다 .
[ 일반화 메소드 ]
[ 일반화 메소드 ]
void CoptyArray<T> (T[]Source , T[]Target)
{
for(int i=0;i<source.Length;i++)
target[i]=source[i];
}
- 형식 자리에 구체적 이름대신 형식 매개변수인 T가 들어간다 .
- 메서드 뒤에 형식 매개변수를 <T>의 형태로 입력해줘야 한다 .
- 호출시 T 대신 형식 이름을 입력하면 컴파일러가 메소드 나머지 부분의 T를 형식 매개변수 값으로 치환한다 .
using System;
using System.Collections;
namespace CopyingList;
class MainApp
{
static void CopyingArray<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];
CopyingArray<int>(source, target);
foreach(int element in target)
Console.WriteLine(element);
string[] source2 = { "하나", "둘", "셋", "넷", "다섯" };
string[] target2 = new string[source2.Length];
CopyingArray<string>(source2, target2);
foreach (string element in target2)
Console.WriteLine(element);
}
}
[ 일반화 클래스 ]
[ 일반화 클래스 ]
class Array_Generic<T>
{
private T[]Array;
public T GetElement(int index){return array[index];}
}
Array_Genenric<int>intArr = new Array_Generic<int>();
Array_Genenric<double>dbArr = new Array_Generic<double>();
- 데이터 형식을 일반화한 클래스
- 기능이 같지만 내부적으로 사용하는 데이터 형식만이 다른 경우 일반화 할 수 있다 .
using System;
using System.Collections;
namespace Generic;
class MainApp
{
class MyList<T>
{
T[] array;
public MyList()
{
array = new T[3];
}
public T this[int index]
{
get { return array[index]; }
set
{
if (index >= array.Length)
{
Array.Resize(ref array, index + 1);
Console.WriteLine($"Array Resized : {array.Length}");
}
array[index] = value;
}
}
public int Length
{
get { return array.Length; }
}
}
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] = "jki";
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 절과 함께 사용할 수 있는 제약 조건은 아래와 같다 .
제약 | 설명 |
where T:struct | T는 값 형식이어야 한다 . |
where T:class | T는 참조형식이어야 한다 . |
where T:new() | T는 반드시 매개변수가 없는 생성자가 있어야 한다 . |
where T:기반 클래스 이름 | T는 명시한 기반 클래스의 파생 클래스이어야 한다 . |
where T: 인터페이스 이름 | T는 명시한 인터페이스를 반드시 구현해야 한다 .복수도 가능 |
where T:U | T는 또다른 형식 매개변수 U로부터 상속받은 클래스여야 한다 |
using System;
using System.Collections;
using System.Dynamic;
namespace ConstraintsOnTypeParameters;
class StructArray<T> where T:struct
{
public T[]Array { get; set; }
public StructArray(int size)
{
Array = new T[size];
}
}
class RefArray<T> where T : class
{
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 CopyArray<T>(T[]source)where T : U
{
source.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;
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);
BaseArray<Base> c = new BaseArray<Base>(3);
c.Array[0] = new Base();
c.Array[1] = new Derived();
c.Array[2] = CreateInstance<Base>();
BaseArray<Derived> d = new BaseArray<Derived>(3);
d.Array[0] = new Derived();
//d.Array[1] = new Base(); Base 형식은 할당 할 수 없다
d.Array[1]= CreateInstance<Derived>();
BaseArray<Derived> e=new BaseArray<Derived>(3);
e.CopyArray(d.Array);
}
}
[ 일반화 컬렉션 ]
[ 일반화 컬렉션 ]
- 컬렉션 클래스들은 object 형식 기반이기에 성능문제가 존재했다 . (컬렉션 요소에 접근시마다 형식변환이 일어나기에)
- 일반화 컬렉션은 컴파일시 컬렉션에서 사용할 형식이 결정 , 형식변환을 일으키지 않고 잘못된 객체를 담지도 않는다 .
[ List<T> ]
- ArrayList와 같은 기능을 한다 .
using System;
using System.Collections;
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 i in list)
Console.WriteLine(i);
Console.WriteLine();
list.RemoveAt(2);
foreach (int i in list)
Console.WriteLine(i);
Console.WriteLine();
list.Insert(2, 2);
foreach (int i in list)
Console.WriteLine(i);
Console.WriteLine();
}
}
[ Queue<T> ]
- Queue와 같은 기능을 한다 .
using System;
using System.Collections;
using System.Collections.Generic;
namespace UsingGenericList;
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());
}
}
[ Stack<T> ]
- Stack과 같은 기능을 한다 .
using System;
using System.Collections;
using System.Collections.Generic;
namespace UsingGenericList;
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());
}
}
[ Dictionary<TKey,TValue> ]
- HashTable의 일반화 버전.키와 밸류 두개의 형식 매개변수를 요구한다 .
using System;
using System.Collections;
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";
Console.WriteLine(dic["하나"]);
Console.WriteLine(dic["둘"]);
Console.WriteLine(dic["셋"]);
}
}
[ foreach를 사용하는 일반화 클래스 ]
[ foreach를 사용할수 있는 일반화 클래스 ]
- 일반화 클래스도 IEnumerable 인터페이스를 상속하면 foreach를 통해 순회 할 수 있지만
요소를 순회할때마다 형식변환을 수행하는 오버로드가 발생한다 .
-이를 위해 IEnumerable<T>인터페이스가 존재한다 .
[ IEnumerable<T> ]
메소드 | 설명 |
IEnumerator GetEnumerator() | IEnumerator 형식의 객체를 반환(IEnumerable로부터 상속받은 메소드) |
IEnumerator<T> GetEnumerator() | IEnumerator<T>형식의 객체를 반환 |
- 형식 변환으로 인한 성능저하가 없으면서도 foreach 순회가 가능한 클래스를 작성 가능하다 .
- 또한 해당 객체는 IEnumerator <T>형식의 객체를 반환하는 GetEnumerator()를 구현해야 한다 .
[ IEnumerator<T> ]
메소드 | 설명 |
boolean MoveNext() | 다음 요소로 이동한다 . 컬렉션의 끝을 지나면 false 이동이 성공하면 true를 반환한다 |
void Reset() | 컬렉션 첫번쨰 위치의 앞으로 이동한다 . |
Object Current{get;} | 컬렉션의 현재 요소를 반환한다 . |
T Current{get;} | 켤렉션의 현재 요소를 반환한다 . |
using System;
using System.Collections;
using System.Collections.Generic;
namespace EnumerableGeneric;
class MyList<T> : IEnumerable<T>, IEnumerator<T>
{
T[] array;
int position = -1;
public MyList() { array = new T[3]; }
public T this[int index]
{
get { return array[index]; }
set
{
if (array.Length <= index)
{
Array.Resize(ref array, index + 1);
Console.WriteLine($"Array Resized : {array.Length}");
}
array[index] = value;
}
}
public int Length { get { return array.Length; } }
#region IEnumerable Method
public IEnumerator<T> GetEnumerator()
{
Console.WriteLine("GetEnumerator T");
return this;
}
IEnumerator IEnumerable.GetEnumerator()
{
Console.WriteLine("GetEnumerator");
return this;
}
#endregion
#region IEnumerator Method
public T Current { get {
Console.WriteLine("Current T");
return array[position];
} }
object IEnumerator.Current { get {
Console.WriteLine("Current");
return array[position]; } }
public void Dispose()
{
}
public bool MoveNext()
{
Console.WriteLine("Move Next");
if (position==array.Length-1)
{
Reset();
return false;
}
position++;
Console.WriteLine($"현재 길이는{ position < array.Length}");
return (position<array.Length);
}
public void Reset()
{
Console.WriteLine("Reset");
position = -1;
}
#endregion
}
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] = 1;
int_list[1] = 2;
int_list[2] = 3;
int_list[3] = 4;
int_list[4] = 5;
foreach(int i in int_list)
Console.WriteLine(i);
}
}
'C# > 이것이 C#이다' 카테고리의 다른 글
[ 이것이 C#이다 ] Chapter 13 . 대리자와 이벤트 (0) | 2024.03.21 |
---|---|
[ 이것이 C#이다 ] Chapter 12 . 예외처리 (0) | 2024.03.20 |
[ 이것이 C#이다 ] Chapter 10 . 배열과 컬렉션 그리고 인덱서 (0) | 2024.03.14 |
[ 이것이 C#이다 ] Chapter 09 . 프로퍼티 (0) | 2024.03.12 |
[ 이것이 C#이다 ] Chapter 08 . 인터페이스와 추상 클래스 (2) | 2024.03.12 |