일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- github
- Python
- 구조체
- Houdini
- 깃
- vim
- 다트 언어
- c# 윈폼
- c언어
- Data Structure
- 포인터
- docker
- Unity
- C# delegate
- Algorithm
- 도커
- jupyter lab
- jupyter
- c#
- 플러터
- C언어 포인터
- c# winform
- c# 추상 클래스
- gitlab
- 유니티
- C++
- HTML
- git
- dart 언어
- Flutter
Archives
- Today
- Total
nomad-programmer
[Programming/C#] 일반화 프로그래밍 : 형식 매개 변수 제약 본문
일반화 메소드나 일반화 클래스가 입력받는 형식 매개 변수 T는 "모든" 데이터 형식을 대신할 수 있다. 이렇게 모든 형식에 대응할 수 있는 형식 매개 변수가 필요한 때도 있지만, 종종 특정 조건을 갖춘 형식에만 대응하는 형식 매개 변수가 필요할 때도 있다.
이 때 형식 매개 변수의 조건에 제약을 줄 수 있다.
예를 들어 MyList<T> 클래스의 형식 매개 변수 T에 "MyClass 로부터 상속받는 형식이어야 할 것" 이라는 제약을 주면 다음과 같이 클래스 선언문의 헤더에 where 절을 추가해주면 된다.
class MyList<T> where T : MyClass
{
// ...
}
일반화 메소드도 비슷하다. CopyArray<T>() 의 형식 매개 변수 T에 "값 형식이어야 할 것" 이라는 제약은 다음과 같이 줄 수 있다.
void CopyArray<T>(T[] source, T[] target) where T : struct
{
for(int i=0; i<source.Length; i++)
{
target[i] = source[i];
}
}
일반화 코드에서 형식을 제약하는 문법은 다음과 같으며, 형식 매개 변수에 대한 일반화 클래스나 일반화 메소드 모두에 동일하게 사용된다.
where 형식매개변수 : 제약조건
제약 조건에는 여러 가지가 올 수 있다. where 절과 함께 사용할 수 있는 제약 조건은 아래와 같다.
제약 조건 | 설명 |
where T : struct | T는 값 형식이어야 한다. |
where T : class | T는 참조 형식이어야 한다. |
where T : new() | T는 반드시 매개 변수가 없는 생성자가 있어야 한다. |
where T : 부모_클래스_이름 | T는 명시한 부모 클래스의 파생 클래스여야 한다. |
where T : 인터페이스_이름 | T는 명시한 인터페이스를 반드시 구현해야 한다. 인터페이스 이름에는 여러 개의 인터페이스를 명시할 수도 있다. |
where T : U | T는 또 다른 형식 매개 변수 U로부터 상속받은 클래스여야 한다. |
제약 조건 where T : new()
CreateInstance<T>() 메소드는 매개 변수가 없는 기본 생성자를 가진 어떤 클래스의 객체라도 생성해준다. 이 메소드를 호출할 때 기본 생성자가 없는 클래스를 형식 매개 변수로 넘기면 컴파일 에러가 발생한다.
public static T CreateInstance<T>() where T: new()
{
return new T();
}
제약 조건 where T : U
CopyArray<T>() 는 소속 클래스인 BaseArray<U> 의 형식 매개 변수 U로부터 T가 상속받아야 할 것을 강제한다.
class BaseArray<U> where U : Base
{
public U[] Array{ get; set; }
public BaseArray(int size)
{
Array = new U[size];
}
// T는 U로부터 상속받은 클래스여야 한다.
public void CopyArray<T>(T[] source) where T : U
{
source.CopyTo(Array, 0);
}
}
일반화 프로그래밍 제약 조건의 예제
using System;
namespace test
{
interface IInterface1
{
void Print1();
}
interface IInterface2
{
void Print2();
}
// T는 값 형식이어야 한다.
class StructArray<T> where T : struct
{
public T[] Array { get; }
public StructArray(int size) => Array = new T[size];
}
// T는 참조 형식이어야 한다.
class RefArray<T> where T : class
{
public T[] Array { get; }
public RefArray(int size) => Array = new T[size];
}
class Base
{
}
class Derived : Base
{
}
// U는 Base클래스 기반의 클래스여야 한다.
class BaseArray<U> where U : Base
{
public U[] Array { get; }
public BaseArray(int size) => Array = new U[size];
// T는 U로부터 상속받은 클래스여야 한다.
public void CopyArray<T>(T[] source) where T : U
{
source.CopyTo(Array, 0);
}
}
// T는 명시한 인터페이스를 반드시 구현해야 한다. 라는 의미의 형식 매개 변수 제약 조건
class FooClass<T> where T : IInterface1, IInterface2, new()
{
public FooClass() => Console.WriteLine("InterClass Called!");
public void PrintFunc()
{
T bar = new T();
bar.Print1();
bar.Print2();
}
}
// 인터페이스를 상속하는 클래스
class InterClass : IInterface1, IInterface2
{
public void Print1()
{
Console.WriteLine("Print1()");
}
public void Print2()
{
Console.WriteLine("Print2()");
}
}
internal class Program
{
// T는 매개 변수가 없는 생성자를 가지고 있어야 한다.
public static T CreateInstance<T>() where T : new()
{
return new T();
}
public static void Main(string[] args)
{
StructArray<int> a = new StructArray<int>(3);
a.Array[0] = 0;
a.Array[1] = 5;
a.Array[2] = 10;
RefArray<StructArray<double>> b = new RefArray<StructArray<double>>(3);
b.Array[0] = new StructArray<double>(5);
b.Array[1] = new StructArray<double>(8);
b.Array[2] = new StructArray<double>(9);
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);
// Base 형식은 이곳에 할당 할 수 없다. 왜냐면 Base에서 파생된 클래스를 형식 매개 변수로 넘겨줬기 때문.
d.Array[0] = new Derived();
d.Array[1] = CreateInstance<Derived>();
d.Array[2] = CreateInstance<Derived>();
BaseArray<Derived> e = new BaseArray<Derived>(3);
e.CopyArray<Derived>(d.Array);
// 인터페이스
FooClass<InterClass> fooClass = new FooClass<InterClass>();
fooClass.PrintFunc();
}
}
}
/* 결과
InterClass Called!
Print1()
Print2()
*/
'Programming > C#' 카테고리의 다른 글
[Programming/C#] 일반화 클래스 : IEnumerable<T>, IEnumerator<T> (0) | 2020.09.20 |
---|---|
[Programming/C#] 일반화 컬렉션 (Generic Collection) (0) | 2020.09.20 |
[Programming/C#] 일반화 프로그래밍 (Generic Programming) (0) | 2020.09.18 |
[Programming/C#] 인덱서 (Indexer) (0) | 2020.09.15 |
[Programming/C#] 컬렉션 (Collection) (0) | 2020.09.14 |
Comments