https://msdn.microsoft.com/ko-kr/library/67ef8sbd.aspx
제네릭
- 필수적 단일 문자 이름으로도 자체 설명이 가능하여 설명적인 이름을 굳이 사용할 필요가 없는 경우가 아니면 제네릭 형식 매개 변수 이름을 설명적인 이름으로 지정하십시오.
public interface ISessionChannel<TSession> { /*...*/ } public delegate TOutput Converter<TInput, TOutput>(TInput from); public class List<T> { /*...*/ }
- 선택적 단일 문자 형식 매개 변수를 사용하는 형식에는 형식 매개 변수 이름으로 T를 사용하십시오.
public int IComparer<T>() { return 0; } public delegate bool Predicate<T>(T item); public struct Nullable<T> where T : struct { /*...*/ }
- 필수적 설명적인 형식 매개 변수 이름 앞에 “T”를 붙이십시오.
public interface ISessionChannel<TSession> { TSession Session { get; } }
- 선택적 매개 변수 이름 안에서 형식 매개 변수에 적용되는 제약 조건을 나타내십시오. 예를 들어 ISession으로 제한되는 매개 변수의 이름은TSession이 될 수 있습니다.
대리자는 자체 형식 매개 변수를 정의할 수 있습니다. 제네릭 대리자를 참조하는 코드에서는 제네릭 클래스를 인스턴스화하거나 제네릭 메서드를 호출할 때와 마찬가지로 다음 예제와 같이 형식 매개 변수를 지정하여 폐쇄형 구성 형식을 만들 수 있습니다.
public delegate void Del<T>(T item); public static void Notify(int i) { } Del<int> m1 = new Del<int>(Notify);
C# 버전 2.0에는 메서드 그룹 변환이라는 새로운 기능이 있습니다. 이 기능은 제네릭 대리자뿐만 아니라 구체적인 대리자에도 적용되며, 이를 통해 위 코드를 다음과 같이 단순화된 구문으로 작성할 수 있습니다.
Del<int> m2 = Notify;
제네릭 클래스 및 메서드에서 다음과 같은 내용을 미리 알지 못하는 경우 매개 변수화된 형식 T에 기본값을 할당하는 방법에 대한 문제가 발생합니다.
- T가 참조 형식인지 값 형식인지 여부
- T가 값 형식인 경우 숫자 값인지 구조체인지 여부
t가 매개 변수화된 형식 T의 변수인 경우 "t = null"과 같은 구문은 T가 참조 형식인 경우에만 유효하고 "t = 0"은 구조체가 아닌 숫자 값 형식인 경우에만 사용할 수 있습니다. 참조 형식에 대해서는 null을 반환하고 숫자 값 형식에는 0을 반환하는 default 키워드를 사용하면 이 문제를 해결할 수 있습니다. 구조체에 대해서는 멤버가 값 형식인지 참조 형식인지 여부에 따라 0 또는 null로 초기화된 구조체의 각 멤버가 반환됩니다. null 허용 값 형식의 경우 default는 다른 구조체와 같이 초기화되는System.Nullable<T>을 반환합니다.
예제가 좀 이상한데..https://msdn.microsoft.com/ko-kr/library/c6cyy67b.aspx
다음은 C# 제네릭과 C++ 템플릿 간의 주요 차이점입니다.
- C# 제네릭은 C++ 템플릿과 같은 정도의 융통성을 제공하지 않습니다. 예를 들어, C# 제네릭 클래스에서 사용자 정의 연산자를 호출할 수는 있지만 산술 연산자를 호출할 수는 없습니다.
- C#에서는 template C<int i> {} 같은 비형식 템플릿 매개 변수를 허용하지 않습니다.
- C#에서는 명시적 특수화를 지원하지 않습니다. 즉, 특정 형식에 대한 템플릿을 사용자 지정하여 구현할 수 없습니다.
- C#에서는 부분 특수화를 지원하지 않습니다. 즉, 형식 인수의 하위 집합을 사용자 지정하여 구현할 수 없습니다.
- C#에서는 형식 매개 변수를 제네릭 형식에 대한 기본 클래스로 사용할 수 없습니다.
- C#에서는 형식 매개 변수에 기본 형식을 사용할 수 없습니다.
- C#에서는 생성된 형식을 제네릭으로 사용할 수는 있지만 제네릭 형식 매개 변수 자체가 제네릭이 될 수는 없습니다.C++에서는 템플릿 매개 변수를 허용합니다.
- C++에서는 템플릿의 모든 형식 매개 변수에 대해서는 유효하지 않을 수 있는 코드가 허용되며 이러한 코드는 형식 매개 변수로 사용되는 특정 형식에 대해 검사를 받습니다. C#에서는 제약 조건을 충족하는 모든 형식과 함께 사용할 수 있도록 클래스의 코드를 작성해야 합니다. 예를 들어, C++의 경우 형식 매개 변수의 개체에 대해 + 및 - 산술 연산자를 사용하는 함수를 작성할 수 있습니다. 이 경우 이러한 연산자를 지원하지 않는 형식으로 템플릿을 인스턴스화할 때 오류가 발생합니다. C#에서는 이러한 함수를 작성할 수 없고 제약 조건에서 추론 가능한 언어 구문만 사용할 수 있습니다.
https://msdn.microsoft.com/ko-kr/library/f4a6ta2h.aspx
제네릭 형식 또는 메서드가 MSIL(Microsoft Intermediate Language)로 컴파일되면 자체적으로 형식 매개 변수를 갖는 것으로 식별하는 메타데이터가 포함됩니다. 제네릭 형식의 MSIL이 사용되는 방식은 제공된 형식 매개 변수가 값 형식인지 참조 형식인지에 따라 다릅니다.
값 형식을 매개 변수로 사용하여 제네릭 형식을 처음 생성할 경우 런타임에서는 제공된 매개 변수를 MSIL의 해당 위치에 대체하여 특수화된 제네릭 형식을 만듭니다. 고유한 값 형식이 매개 변수로 사용될 때마다 특수화된 제네릭 형식이 만들어집니다.
참조 형식의 수는 프로그램마다 크게 다를 수 있으므로, 제네릭을 C# 방식으로 구현하면 컴파일러가 참조 형식의 제네릭 클래스에 대해 만드는 특수화된 클래스의 수가 1개로 줄어들어 코드가 매우 간결해집니다.
뿐만 아니라, 값 형식 또는 참조 형식 매개 변수를 사용하여 제네릭 C# 클래스가 인스턴스화되면 런타임에 리플렉션을 통해 쿼리할 수 있고 실제 형식과 형식 매개 변수를 모두 조사할 수 있습니다.
value type은 형식에 따라서 인스턴스 생성 후 재사용 reference type은 각각 인스턴스 생성https://msdn.microsoft.com/ko-kr/library/ac30fak4.aspx
.NET Framework 클래스 라이브러리 버전 2.0에서는 System.Collections.Generic이라는 새로운 네임스페이스를 제공하며, 이 네임스페이스에는 바로 사용할 수 있는 제네릭 컬렉션 클래스 및 관련 인터페이스가 있습니다. System 같은 기타 네임스페이스에서도 IComparable<T> 같은 새로운 제네릭 인터페이스를 제공합니다. 이러한 클래스 및 인터페이스는 이전 버전의 .NET Framework에서 제공하던 제네릭이 아닌 컬렉션 클래스보다 효율적이고 형식 안전적입니다. 사용자 지정 컬렉션 클래스를 디자인하고 구현하기 전에 .NET Framework 클래스 라이브러리에서 제공하는 클래스를 사용하거나 파생시킬 수 있는지 고려해 보십시오.
인덱서
https://msdn.microsoft.com/ko-kr/library/6x16t2tx.aspxclass SampleCollection<T> { // Declare an array to store the data elements. private T[] arr = new T[100]; // Define the indexer, which will allow client code // to use [] notation on the class instance itself. // (See line 2 of code in Main below.) public T this[int i] { get { // This indexer is very simple, and just returns or sets // the corresponding element from the internal array. return arr[i]; } set { arr[i] = value; } } } // This class shows how client code uses the indexer. class Program { static void Main(string[] args) { // Declare an instance of the SampleCollection type. SampleCollection<string> stringCollection = new SampleCollection<string>(); // Use [] notation on the type. stringCollection[0] = "Hello, World"; System.Console.WriteLine(stringCollection[0]); } } // Output: // Hello, World.
클래스나 구조체에 대한 인덱서를 선언하려면 다음 예제에서와 같이 this 키워드를 사용합니다.
public int this[int index] // Indexer declaration { // get and set accessors }
인덱서 형식과 해당 매개 변수 형식에는 적어도 인덱서 자체와 동등한 수준으로 액세스할 수 있어야 합니다.액세스 가능성 수준에 대한 자세한 내용은 액세스 한정자를 참조하십시오.
인터페이스와 함께 인덱서를 사용하는 방법에 대한 자세한 내용은 인터페이스 인덱서를 참조하십시오.
인덱서 시그니처는 인덱서 정식 매개 변수의 수 및 형식으로 구성됩니다.이 시그니처는 인덱서 형식 또는 정식 매개 변수 이름을 포함하지 않습니다.같은 클래스에 두 개 이상의 인덱서를 선언한 경우, 모든 인덱서가 다른 시그니처를 가져야 합니다.
다른 언어에서 사용할 수 있는 이름을 인덱서에 부여하려면 선언에 name 특성을 사용합니다.예를 들면 다음과 같습니다.
[System.Runtime.CompilerServices.IndexerName("TheItem")] public int this [int index] // Indexer declaration { }
이 인덱서의 이름은 TheItem입니다.name 특성을 제공하지 않으면 기본 이름으로 Item이 사용됩니다.
이 예제에서는 요일을 저장하는 클래스를 선언합니다.문자열과 요일 이름을 가져오고 상응하는 정수를 반환하는 get 접근자를 선언합니다.예를 들어, 일요일은 0을 반환하고 월요일은 1을 반환하는 방식입니다.
// Using a string as an indexer value class DayCollection { string[] days = { "Sun", "Mon", "Tues", "Wed", "Thurs", "Fri", "Sat" }; // This method finds the day or returns -1 private int GetDay(string testDay) { for (int j = 0; j < days.Length; j++) { if (days[j] == testDay) { return j; } } throw new System.ArgumentOutOfRangeException(testDay, "testDay must be in the form \"Sun\", \"Mon\", etc"); } // The get accessor returns an integer for a given string public int this[string day] { get { return (GetDay(day)); } } }
interface(C# 참조) 에서 인덱서를 선언할 수 있습니다. 인터페이스 인덱서의 접근자와 클래스 인덱서의 접근자는 다음과 같은 차이점이 있습니다.
- 인터페이스 접근자는 한정자를 사용하지 않습니다.
- 인터페이스 접근자에는 본문이 없습니다.
따라서 접근자의 목적은 인덱서가 읽기/쓰기, 읽기 전용 또는 쓰기 전용인지 여부를 나타내는 것입니다.
다음은 인터페이스 인덱서 접근자의 예제입니다.
public interface ISomeInterface { //... // Indexer declaration: string this[int index] { get; set; } }
https://msdn.microsoft.com/ko-kr/library/4bsztef7.aspx
인덱서는 속성과 비슷합니다. 다음 표에 나와 있는 차이점을 제외하면 접근자에 정의된 모든 규칙이 인덱서 접근자에도 적용됩니다.
Property
|
인덱서
|
---|---|
공용 데이터 멤버인 것처럼 메서드를 호출할 수 있습니다.
|
개체 자체의 배열 표기법을 사용하여 개체의 내부 컬렉션 요소에 액세스할 수 있습니다.
|
단순한 이름을 통해 액세스할 수 있습니다.
|
인덱스를 통해 액세스할 수 있습니다.
|
정적 또는 인스턴스 멤버가 될 수 있습니다.
|
인스턴스 멤버여야 합니다.
|
속성의 get 접근자에는 매개 변수가 없습니다.
|
인덱서의 get 접근자는 인덱서와 동일한 정식 매개 변수 목록을 가집니다.
|
속성의 set 접근자에는 명시적인 value 매개 변수가 포함됩니다.
|
인덱서의 set 접근자는 value 매개 변수 외에도 인덱서와 동일한 정식 매개 변수 목록을 가집니다.
|
자동으로 구현된 속성(C# 프로그래밍 가이드) 이 있는 약식 구문을 지원합니다.
|
약식 구문을 지원하지 않습니다.
|
인터페이스
https://msdn.microsoft.com/ko-KR/library/ms173156.aspx
C# 언어는 클래스에 대한 다중 상속을 지원하지 않기 때문에, 해당 기능이 중요합니다. 또한 구조체는 다른 구조체나 클래스에서 실제로 상속할 수 없기 때문에 구조체에 대한 상속을 시뮬레이트하려는 경우 인터페이스를 사용해야 합니다.
다음 예제에서는 인터페이스 키워드를 사용하여 인터페이스를 정의하는 방법을 보여줍니다.
interface IEquatable<T> { bool Equals(T obj); }
인터페이스에는 다음과 같은 속성이 있습니다.
- 인터페이스는 추상 기본 클래스와 같습니다. 인터페이스를 구현하는 모든 클래스 또는 구조체는 모든 멤버를 구현해야 합니다.
- 인터페이스는 직접 인스턴스화할 수 없습니다.해당 멤버는 인터페이스를 구현하는 클래스 또는 구조체에 의해 구현됩니다.
- 인터페이스는 이벤트, 인덱서, 메서드 및 속성을 포함할 수 있습니다.
- 인터페이스에는 메서드의 구현이 포함되지 않습니다.
- 클래스 또는 구조체는 여러 인터페이스를 구현할 수 있습니다.클래스는 기본 클래스를 상속할 수 있으며 하나 이상의 인터페이스를 제공할 수도 있습니다.
클래스에서 시그니처가 동일한 멤버가 들어 있는 두 인터페이스를 구현하는 경우 클래스에서 이 멤버를 구현하면 두 인터페이스 모두에서 이 멤버를 해당 구현으로 사용하게 됩니다.
그러나 두 인터페이스 멤버가 동일한 기능을 수행하지 않는 경우에는 인터페이스 하나 또는 모두의 구현이 잘못될 수 있습니다.인터페이스를 통해서만 호출되고 특정 인터페이스에만 관련되는 클래스 멤버를 만드는 방식으로 인터페이스 멤버를 명시적으로 구현할 수 있습니다. 이렇게 하려면 인터페이스 이름과 마침표를 사용하여 클래스 멤버의 이름을 지정해야 합니다. 예를 들면 다음과 같습니다.
public class SampleClass : IControl, ISurface { void IControl.Paint() { System.Console.WriteLine("IControl.Paint"); } void ISurface.Paint() { System.Console.WriteLine("ISurface.Paint"); } }
댓글 없음:
댓글 쓰기