>  기사  >  백엔드 개발  >  제네릭의 개요 및 구체적인 용도

제네릭의 개요 및 구체적인 용도

零下一度
零下一度원래의
2017-06-23 16:32:421544검색

1. 제네릭 개요

제네릭 클래스와 제네릭 메서드는 재사용성, 유형 안전성고효율성을 결합하며 이는 해당 비제네릭 클래스 및 메서드의 범위를 벗어납니다. 제네릭은 컨테이너(컬렉션) 및 컨테이너에서 작동하는 메서드에 널리 사용됩니다. .NET Framework 2.0 클래스 라이브러리는 몇 가지 새로운 제네릭 기반 컨테이너 클래스를 포함하는 새로운 네임스페이스 System.Collections.Generic을 제공합니다.

  1. 제네릭의 변수 유형 매개변수: T가 일반적으로 사용되지만 키워드가 아닌 단어와 예약어도 사용할 수 있습니다.

  2. 모든 변수 유형 T는 컴파일 시 자리 표시자를 사용합니다. 모든 점 기호는 런타임에 전달된 실제 유형으로 대체됩니다.

2. 제네릭의 장점

초기 버전의 공용 언어 런타임 및 C# 언어 제한 사항에 대해 제네릭은 솔루션을 제공합니다. 이전 유형의 일반화는 유형을 전역 기본 클래스 System.Object로 변환하여 달성되었습니다. .NET Framework 기본 클래스 라이브러리의 ArrayList 컨테이너 클래스가 이러한 제한 사항의 예입니다. ArrayList는 사용 중에 참조 유형이나 값 유형을 변경하지 않고 저장할 수 있는 매우 편리한 컨테이너 클래스입니다.

ArrayList list = new ArrayList();
list.Add(1);
list.Add(175.50);
list.Add("헬로키티");

double sum = 0;
foreach(int value in list)
{
sum += value;
}

단점:

편의성에는 대가가 따르기 때문에 ArrayList에 추가된 모든 참조 유형이나 값 유형을 탄력적으로 숨겨야 합니다. System.Object로 업캐스트됩니다. 요소가 값 유형인 경우 목록에 추가할 때 boxing하고 검색할 때 unboxing해야 합니다. 유형 변환, 박싱 및 언박싱 작업은 모두 성능을 저하시키며, 대형 컨테이너를 반복해야 하는 경우 박싱 및 언박싱의 영향이 심각할 수 있습니다. 또 다른 제한 사항은 컴파일 시간 유형 검사가 부족하다는 것입니다. ArrayList가 모든 유형을 Object로 변환하면 컴파일 시간에 고객 코드에서 sum+=vlaue와 같은 오류를 방지할 수 없습니다.

System.Collections.Generic 네임스페이스에서; List 컨테이너의 경우 다음과 유사하게 컨테이너에 요소를 추가하는 작업이 수행됩니다.

List listInt = new List();
listInt.Add(100 );
listInt.Add (200) )
                                               합계 += 값; 약간 더 복잡한 코드에 대한 보상은 생성한 테이블이 ArrayList보다 안전할 뿐만 아니라 특히 테이블의 요소가 값 유형인 경우 훨씬 더 빠르다는 것입니다.

3. 제네릭 유형 매개변수


제네릭 유형 또는 제네릭 메소드 정의에서 유형 매개변수는 일반적으로 대문자인 자리 표시자입니다(비키워드 및 예약어 이름을 사용할 수도 있음). 티. 클라이언트 코드가 이 유형의 변수를 선언하고 인스턴스화하는 경우 T를 클라이언트 코드에서 지정한 데이터 유형으로 바꿉니다. Generics에 제공된 List 클래스와 같은 일반 클래스는 실제 유형이 아니라 유형의 청사진에 더 가깝기 때문에 있는 그대로 사용할 수 없습니다. MyList를 사용하려면 클라이언트 코드는 꺾쇠 괄호 안에 유형 매개변수를 지정하여 생성된 유형을 선언하고 인스턴스화해야 합니다. 이 특정 클래스의 유형 매개변수는 컴파일러가 인식하는 모든 유형이 될 수 있습니다. 다음과 같이 각각 다른 유형 매개변수를 사용하여 생성된 유형의 인스턴스를 원하는 수만큼 생성할 수 있습니다.

List listInt = new List();

List List();List listString = 새로운 List();

4. 제네릭 유형 매개변수에 대한 제약

제네릭은 다음과 같은 5가지 제약을 제공합니다:

여기서 T : class여기서 T : new()여기서 T : <기본 클래스 이름>여기서 T: <인터페이스 이름>
Constraint Description
여기서 T: 매개변수 유형은 값이어야 합니다.
매개변수 유형은 참조 유형이어야 합니다
매개변수 유형에는 인수가 없는 공개 생성자가 있어야 합니다. 다른 제약 조건과 함께 사용되는 경우 new() 제약 조건은 마지막에 배치되어야 합니다.
매개변수 유형은 지정된 기본 유형이거나 지정된 기본 유형에서 파생된 하위 클래스여야 합니다.
매개변수 유형 지정된 인터페이스이거나 지정된 인터페이스의 구현이어야 합니다. 여러 인터페이스에 대해 제약 조건을 지정할 수 있습니다. 인터페이스 제약조건은 일반적일 수도 있습니다.
제한되지 않은 유형 매개변수:

  1. 특정 유형 매개변수가 이러한 연산자를 지원한다는 보장이 없기 때문에 변경 가능한 유형의 인스턴스를 비교하는 데 != 및 ==를 사용할 수 없습니다. System.Object로 변환하거나 모든 인터페이스 유형으로 명시적으로 변환할 수 있습니다.

  2. null과 비교할 수 있습니다. 규정되지 않은 유형 매개변수를 널과 비교하는 경우 유형 매개변수가 값 유형이면 비교 결과는 항상 false입니다.

  3. 유형 제약 조건 없음:

    제약 조건이 일반 유형 매개 변수인 경우 이를 Naked 유형 제약 조건이라고 합니다.

class List{        void Add(List 항목) 여기서 U는 다음과 같습니다.

위 예에서 Add 메서드 컨텍스트의 T는 형식화되지 않은 제약 조건인 반면 List 클래스 컨텍스트의 T는 무제한 형식 매개 변수입니다.

형식화되지 않은 제약 조건은 일반 클래스 정의에도 사용할 수 있습니다. 유형이 지정되지 않은 제약 조건은 다른 유형 매개 변수와 함께 꺾쇠 괄호 안에 선언해야 합니다.

//naked 유형 제약 조건

public class MyClass 여기서 T : V

컴파일러는 형식화되지 않은 제약 조건만 System.Object에서 상속되는 것으로 간주하므로 형식화되지 않은 제약 조건이 있는 일반 클래스의 사용은 매우 제한됩니다. 두 유형 매개변수 간의 상속 관계를 적용하려면 제네릭 클래스에 유형화되지 않은 제약 조건을 사용하세요.

5. 일반 클래스

일반 클래스는 특정 데이터 유형에 국한되지 않는 작업을 캡슐화합니다. 일반 클래스는 연결 목록, 해시 테이블, 스택, 큐, 트리 등과 같은 컨테이너 클래스에서 자주 사용됩니다. 컨테이너에서 요소를 추가하고 제거하는 등 이러한 클래스의 작업은 저장된 데이터 유형에 관계없이 거의 동일한 작업을 수행합니다.

일반적으로 기존의 구체적인 클래스에서 일반 클래스를 만들고 일반성과 유용성 사이에서 최상의 균형을 얻을 때까지 한 번에 하나씩 유형 매개변수로 유형을 변경합니다. 자신만의 일반 클래스를 만들 때 고려해야 할 중요한 사항은 다음과 같습니다.

  • 어떤 유형을 유형 매개변수로 일반화해야 하는지. 일반적인 규칙은 매개변수로 표현되는 유형이 많을수록 코드의 유연성과 재사용성이 높아진다는 것입니다. 너무 많은 일반화는 다른 개발자가 코드를 이해하기 어렵게 만들 수 있습니다.

  • 제약조건이 있는 경우 유형 매개변수에는 어떤 종류의 제약조건이 필요합니까? 좋은 방법은 처리해야 하는 모든 유형이 처리될 수 있도록 보장하면서 가능한 가장 큰 제약 조건을 사용하는 것입니다. 예를 들어, 일반 클래스가 참조 유형만 사용한다는 것을 알고 있다면 해당 클래스에 대한 제약 조건을 적용하세요. 이를 통해 실수로 값 유형을 사용하는 것을 방지하고 T에서 as 연산자를 사용하고

  • 기본 클래스 또는 하위 클래스에 일반 동작을 배치할 수 있습니다. 일반 클래스를 기본 클래스로 사용할 수 있습니다. 이는 제네릭이 아닌 클래스를 디자인할 때도 고려해야 합니다. 일반 기본 클래스에 대한 상속 규칙

  • 하나 이상의 일반 인터페이스를 구현할지 여부. 예를 들어 제네릭 기반 컨테이너에서 요소를 생성하는 클래스를 디자인하려면 IComparable과 같은 인터페이스를 구현해야 할 수 있습니다. 여기서 T는 클래스의 매개변수입니다.

일반 클래스 Node의 경우 클라이언트 코드는 유형 매개변수를 지정하여 폐쇄형 생성 유형(Node)을 생성하거나 유형 매개변수를 지정하지 않은 채로 둘 수 있습니다(예: 일반 유형 Base 지정). 개방형 구성 유형(Node)을 생성하는 클래스입니다. 일반 클래스는 구상 클래스, 폐쇄형 생성 유형 또는 개방형 생성 유형에서 상속할 수 있습니다.

// 구상 유형
class Node : BaseNode
//폐쇄형 생성 유형
class Node ;int>
//open constructor type
class Node : BaseNode

비제네릭 구체적 클래스는 폐쇄형 구성 기본 클래스에서 상속할 수 있지만 개방형 구성 기본 클래스에서는 상속할 수 없습니다. 수업. 이는 클라이언트 코드가 기본 클래스에 필요한 유형 매개변수를 제공할 수 없기 때문입니다.

//오류 없음.
class Node : BaseNode
//오류를 생성합니다.
class Node: BaseNode< T>

일반 유형의 구체적인 클래스는 개방형 생성 유형에서 상속할 수 있습니다. 하위 클래스와 공유되는 유형 매개변수를 제외하고 모든 유형 매개변수에 유형을 지정해야 합니다.

//오류를 생성합니다.
class Node : BaseNode .
class Node : BaseNode {…}

개방형 구조 유형, 매개변수 유형 및 제약 조건을 지정해야 합니다.

class NodeItem where T : IComparable, new() {…}

class MyNodeItem : NodeItem where T : IComparable, new() {…}

일반 유형은 다양한 유형 매개변수 및 제약조건을 사용할 수 있습니다.

개방형 및 폐쇄형 생성 유형을 메소드의 매개변수로 사용할 수 있습니다:

class KeyType {…}

class SuperKeyType 여기서 U : IComparable 뷔 : new() {…}

void Swap(List list1, List list2) {…}
void Swap(List list2) {…}

6. 일반 인터페이스

인터페이스를 유형 매개변수에 대한 제약조건으로 지정하는 경우 해당 인터페이스를 구현하는 유형만 사용할 수 있습니다. 매개변수를 입력합니다. 다음과 같이 여러 인터페이스를 유형의 제약 조건으로 지정할 수 있습니다. 인터페이스는 다음과 같이 여러 유형 매개변수를 정의할 수 있습니다.

IDictionary인터페이스와 클래스의 상속 규칙은 동일합니다.

//알겠습니다. IMyInterface: IBaseInterface
//알겠습니다.

IMyInterface : IBaseInterface2

//Okay.class MyClass : IBaseInterface

//Okay.class MyClass IBaseInterface 7. 제네릭 메소드




일반 클래스, 일반 구조 및 일반 인터페이스에는 모두 동일한 메서드 오버로드 규칙이 있습니다.




제네릭 메소드는 다음과 같이 유형 매개변수를 선언하는 메소드입니다.

void Swap(ref T lhs, ref T rhs) lhs = rhs; rhs = temp;}
{

T temp;

temp = lhs;

다음 샘플 코드는 int를 유형 매개변수로 사용하여 메소드를 호출하는 예를 보여줍니다. int a = 1;int b = 2;//…




Swap(a, b);

유형 매개변수를 무시할 수도 있으며 컴파일러는 가서 추론해 보세요. Swap을 호출하는 다음 코드는 위의 예제와 동일합니다.

Swap(a, b);


정적 메서드와 인스턴스 메서드는 동일한 유형 추론 규칙을 갖습니다. 컴파일러는 전달된 메서드 매개변수를 기반으로 형식 매개변수를 추론할 수 있습니다. 이는 제약 조건이나 반환 값만으로는 결정할 수 없습니다. 따라서 매개변수가 없는 메소드의 경우 유형 추론이 유효하지 않습니다. 형식 유추는 컴파일러가 오버로드된 메서드 플래그를 확인하기 전인 컴파일 타임에 발생합니다. 컴파일러는 동일한 이름을 가진 모든 제네릭 메서드에 형식 유추 논리를 적용합니다. 오버로딩 확인 단계에서 컴파일러는 형식 유추에 성공한 제네릭 클래스만 포함합니다.



일반 클래스에서 제네릭이 아닌 메서드는 클래스의 유형 매개변수에 액세스할 수 있습니다.

class List

{ ​ void Swap(ref T lhs, ref T rhs) { ... }}



일반 클래스에서 해당 클래스와 동일한 유형 매개변수를 사용하여 일반 메소드를 정의하면 컴파일러에서 경고 CS0693을 생성합니다. .

class List T>"의 유형 매개변수 이름이 동일합니다

제네릭 클래스에서 정의되지 않은 유형 매개변수를 정의하는 제네릭 메서드를 정의합니다. (일반적으로 사용되지 않음, 일반적으로 제약 조건과 함께 사용됨)

class List
{
        void Swap< u & gt; (ref t lhs, ref t rhs) {// 일반적으로 사용되지 않음

void add; u & gt; (list & lt; u & gt; 항목) 여기서 u : t {} // 일반적으로 사용되는}}

일반 메소드는 여러 유형 매개변수로 오버로드됩니다. 예를 들어, 다음 메서드를 동일한 클래스에 배치할 수 있습니다.

void DoSomething() { }

void DoSomething() { }
void DoSomething() { }

8. 제네릭의 기본 키워드

제네릭 클래스 및 제네릭 메소드에서 발생하는 문제는 매개변수화된 유형에 기본값을 할당하는 방법을 현재로서는 알 수 없습니다. 다음 두 가지 사항을 미리 확인하세요.

  1. T는 값 유형 또는 참조 유형이 됩니다.

  2. T가 값 유형이면 T는 숫자 값 또는 구조가 됩니다.

매개변수화된 유형의 경우 T의 변수 t에 대해 t = null 문은 T가 참조 유형인 경우에만 유효합니다. t = 0은 숫자 값에만 유효하고 구조에는 유효하지 않습니다. 이 문제에 대한 해결책은 참조 유형에 대해 null을 반환하고 값 유형에 대해 0을 반환하는 default 키워드를 사용하는 것입니다. 구조의 경우 구조의 각 멤버를 반환하고 멤버가 값 유형인지 참조 유형인지에 따라 0 또는 null을 반환합니다.

class GenericClass <

위 내용은 제네릭의 개요 및 구체적인 용도의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.