>  기사  >  백엔드 개발  >  C# 일반 프로그래밍

C# 일반 프로그래밍

黄舟
黄舟원래의
2016-12-21 14:47:351019검색

제네릭: 매개변수화된 유형을 사용하여 동일한 코드에서 여러 데이터 유형을 작동합니다. 유연한 재사용을 위해 "매개변수화된 유형"을 사용하여 유형을 추상화하세요.

예제 코드:

class PRogram

{

static void Main(string[] args)

{

int obj = 2;

Test test = new Test(obj);

Console.WriteLine("int:" + test.obj);

string obj2 = "hello world";

Test test1 = new Test(obj2);

Console.WriteLine("String:" + test 1 .obj);

Console.Read();

}

}



클래스 테스트

{

public T obj;

public Test(T obj)

{

this.obj = obj;

}

}

출력 결과는 다음과 같습니다.

int:2

String:hello world



프로그램 분석:

1. 테스트는 일반적인 클래스입니다. T는 인스턴스화할 일반 유형입니다. T가 int 유형으로 인스턴스화되면 멤버 변수 obj는 int 유형입니다. T가 string 유형으로 인스턴스화되면 obj는 string 유형입니다.

2. 위 프로그램은 종류에 따라 다른 값을 표시합니다.



C# 일반 메커니즘:

C# 일반 기능은 런타임 시 CLR에서 지원됩니다. C# 일반 코드는 IL 코드 및 메타데이터로 컴파일할 때 특수 메서드를 사용합니다. 일반 유형 및 일반 작업은 독점 IL 지시문을 사용하여 지원됩니다. 실제 일반 인스턴스화 작업은 JIT 컴파일 중에 "주문형" 방식으로 발생합니다.



지금 코드에서 Main 함수의 메타데이터를 살펴보세요

.method private hidebysig static void Main(string[] args) cil Managed

{

.entrypoint

// 코드 크기 79(0x4f)

.maxstack 2

.locals init ([0] int32 obj,

                                                                                               > 4.2

IL_0002: stloc.0

IL_0003: ldloc .0

IL_0004: newobj 인스턴스 void 클래스 CSharpStudy1.Test`1::.ctor(!0)

IL_0009: stloc.1

IL_000a: " ldstr "int:"

IL_000f: ldloc.1

IL_0010: ldfld !0 class CSharpStudy1.Test`1::obj

IL_0015: 상자 [mscorlib ]System.Int3 2

IL_001a: 호출 문자열 [mscorlib]System.String::Concat(object,

🎜> IL_001f: 호출 void [mscorlib]System.Console::WriteLine(string )

IL_0024: 아니요

IL_0025: ldstr "hello world"

IL_002a: stloc.2

IL_002b: ldloc.2

IL_002c: newobj 인스턴스 void 클래스 CSharpStudy1.Test`1::.ctor(!0)

IL_0031: stloc.3

IL_0032: ldstr "문자열:"

IL_0037: ldloc.3

IL_0038: ldfld !0 클래스 CSharpStudy1.Test`1& lt;string> : :obj

IL_003d: 호출 문자열 [mscorlib]System.String::Concat(string,

String)

IL_0042: 호출 void [mscorlib]System.Console: : WriteLine(string)

IL_0047: nop

IL_0048: call int32 [mscorlib]System.Console::Read()

IL_004d: pop

IL_004 e : ret

} // 메소드 끝 Program::Main



Test 클래스에서 생성자의 메타데이터를 살펴보겠습니다.

.method public hidebysig 특수 이름 rtspecialname

인스턴스 void .ctor(!T obj) cil Managed

{

// 코드 크기 17(0x11)

.maxstack 8

IL_0000: ldarg.0

IL_0001: 인스턴스 호출 void [mscorlib]System.Object::.ctor()

IL_0006: nop

IL_0007 : 아니요

IL_0008: ldarg.0

IL_0009: ldarg.1

IL_000a: stfld !0 클래스 ConsoleCSharpTest1.Test`1 ::obj

IL_000f: nop

IL_0010: ret

} // 메서드 끝 Test`1::.ctor



1. 컴파일 라운드 동안 컴파일러는 IL 코드의 "일반 버전"과 Test 유형에 대한 메타데이터만 생성합니다. 이는 일반 코드를 인스턴스화하지 않으며 T는 중간에 자리 표시자 역할만 합니다. 예: 테스트 유형 메타데이터에 표시된

2. JIT 컴파일 중에 JIT 컴파일러가 처음으로 Test를 발견하면 "일반 버전"이 int로 대체됩니다. IL 코드 및 메타데이터의 T - 일반 유형의 인스턴스화. 예: Main 함수에 표시된

3. CLR은 유형 매개변수가 "참조 유형"인 모든 일반 유형에 대해 동일한 코드를 생성합니다. 각각에 대해 CLR이 별도의 코드를 생성하는 다른 "값 유형"입니다. 참조 유형 제네릭을 인스턴스화할 때는 메모리에 할당되는 크기가 동일하지만 값 유형을 인스턴스화할 때는 메모리에 할당되는 크기가 다르기 때문입니다.



C# 일반 기능:

1. 인스턴스화된 제네릭 유형의 매개변수가 동일한 경우 JIT 편집기는 해당 유형을 재사용하므로 C#의 동적 제네릭은 유형 기능은 C++ 정적 템플릿으로 인해 발생할 수 있는 코드 팽창 문제를 방지합니다.

2. C# 제네릭 유형은 풍부한 메타데이터를 전달하므로 C#의 제네릭 유형은 강력한 리플렉션 기술에 적용될 수 있습니다.

3. C#의 제네릭은 "기본 클래스, 인터페이스, 생성자, 값 유형/참조 유형"의 제약 조건 메서드를 사용하여 유형 매개 변수에 대한 "명시적 제약 조건"을 구현합니다. 이는 유형 안전성뿐 아니라 손실도 향상시킵니다. "서명" 암시적 제약 조건을 기반으로 하는 C++ 템플릿의 높은 유연성



C# 일반 상속:

C# 일반 유형을 별도로 선언할 수 있는 것 외에도( 클래스 및 구조), 기본 클래스에 제네릭 유형의 선언을 포함할 수도 있습니다. 그러나 기본 클래스가 일반 클래스인 경우 해당 유형은 하위 클래스(일반 유형이기도 함)에서 선언된 유형 매개변수에서 인스턴스화되거나 파생됩니다.

class C 🎜>
클래스 D:C

클래스 E:C

클래스 F:C
class G:C //Illegal

E 유형은 위에서 언급한 하위 클래스에서 파생된 C 유형에 대해 U 및 V를 제공합니다.

F 유형은 C를 상속합니다. 개인적으로는 F가 제네릭이 아닌 클래스를 상속한 것으로 간주할 수 있다고 생각합니다.

G 유형은 제네릭이 아니고 C이기 때문에 불법입니다. Generics이므로 G는 C에 일반 인스턴스화를 제공할 수 없습니다



제네릭 유형의 멤버:

제네릭 유형의 멤버는 제네릭 유형 선언에서 유형 매개변수를 사용할 수 있습니다. 그러나 형식 매개 변수에 제약 조건이 없으면 해당 형식의 System.Object에서 상속된 공용 멤버만 사용할 수 있습니다. 아래와 같이:




일반 인터페이스:

일반 인터페이스의 유형 매개변수는 인스턴스화되거나 구현 클래스에 의해 선언된 유형 매개변수에서 파생됩니다



일반 대리자:

일반 대리자는 대리자 반환 값 및 매개 변수에 대한 매개 변수 유형 적용을 지원합니다. 이러한 매개 변수 유형에는 법적 제약 조건이 적용될 수도 있습니다

대리자 bool MyDelegate(T 값);

class MyClass

{

static bool F(int i){...}

static bool G(string s){...}

static void Main()

{

MyDelegate 🎜> MyDelegate p1 = new MyDelegate(F);

}

}



일반 메서드:

1. C# 일반 메커니즘은 "메서드 선언에 형식 매개변수 포함", 즉 일반 메서드만 지원합니다.

2. C# 제네릭 메커니즘은 메서드를 제외한 다른 멤버(속성, 이벤트, 인덱서, 생성자, 소멸자 포함) 선언에 형식 매개 변수를 포함하는 것을 지원하지 않지만 이러한 멤버 자체는 제네릭에 포함될 수 있습니다. 일반 유형의 유형 매개변수를 입력하고 사용하십시오.

3. 제네릭 메소드는 제네릭 유형과 비제네릭 유형 모두에 포함될 수 있습니다.



일반 메서드 선언: 다음과 같습니다

public static int FunctionName(T 값){...}



일반 메소드 오버로딩:

public void Function1(T a);

public void Function1(U a);

이렇게 하면 됩니다. 제네릭 메서드의 오버로드를 구성할 수 없습니다. 컴파일러는 제네릭 유형 T와 U가 다른지 여부를 확인할 수 없기 때문에 두 메서드가 다른지 여부를 확인할 수 없습니다.



public void Function1(int x);

public void Function1(int x);

이는 오버로드를 구성할 수 있습니다



public void Function1(T t) where T:A;

public void Function1(T t) where T:B;

이것은 일반 메소드의 오버로딩을 구성할 수 없습니다. 컴파일러는 제약 조건의 A와 B가 다른지 여부를 확인할 수 없기 때문에 두 메서드가 다른지 여부를 확인할 수 없습니다.



일반 메서드 재작성:

재작성 중 프로세스에서는 추상 클래스의 추상 메서드 제약 조건이 기본적으로 상속됩니다. 다음과 같습니다:

추상 클래스 Base

{

public abstract T F(T t,U u) where U:T;

공개 요약 T G(T t) 여기서 T:IComparable;

}



class MyClass:Base

{

public override
}

MyClass의 두 가지 재정의된 메서드의 경우

F 메서드가 유효하며 제약 조건은 기본적으로

상속됩니다. G 메서드가 잘못되었습니다. 모든 제약 조건이 중복됩니다.



일반 제약 조건:

1. C# 제네릭에는 "모든 제네릭 형식 또는 제네릭 메서드의 형식 매개 변수"에 대한 제약 조건이 필요합니다. 가정은 C#에서 요구하는 형식 안전성을 유지하기 위한 "명시적 제약 조건"을 기반으로 합니다.

2. "명시적 제약 조건"은 where 절로 표현됩니다. "기본 클래스 제약 조건", "인터페이스 제약 조건", "생성자 제약 조건" 및 "값 유형/참조 유형 제약 조건"의 네 가지 유형을 지정할 수 있습니다. ". .

3. "명시적 제약 조건"이 필요하지 않습니다. "명시적 제약 조건"이 지정되지 않으면 일반 형식 매개 변수는 System.Object 형식의 공용 메서드에만 액세스할 수 있습니다. 예: 초기 예에서는 obj 멤버 변수가 정의되었습니다. 예를 들어, 초기 예제에 Test1 클래스를 추가하고 아래와 같이 두 개의 공용 메소드 Func1 및 Func2를 정의합니다.






아래 다음 제약 조건 분석을 시작하세요.

기본 클래스 제약 조건:

class A

{

public void Func1()

{ }

}



클래스 B

{

public void Func2()

{ }

}



class C

where S : A

where T : B

{

공개 C(S s,T t)

{

//S의 변수는 Func1 메소드를 호출할 수 있습니다

                 s.Func1() >
}

}

인터페이스 제약 조건:

인터페이스 IA< ;T>

{

T Func1()

}



인터페이스 IB

{

void Func2();

}



인터페이스 IC

{

class MyClass< T, V>

where T : IA
where V : IB, IC

{

public MyClass (T, v)
{

// T는 Func1을 호출할 수 있습니다

T.Func1 ()

// v 객체는 Func2 및 Func3을 호출할 수 있습니다

            v.Func2(); 🎜> 생성자 제약 조건:

클래스 A

                                                                        🎜>

B급

🎜>


클래스 C 여기서 T : new()

{

T t;

public C()

           

t = 새로운 T();

}

}



클래스 D

          {

          공개 무효 Func()

                                                                                                       C d = 새로운 C();

}

}

d 객체를 컴파일할 때 오류가 발생합니다. 제네릭 유형 또는 메서드 C

에서 매개 변수 'T'로 사용하려면 유형 B에 매개 변수가 없는 공용 생성자가 있어야 합니다. 참고: C#에서는 이제 no-만 지원합니다. 매개변수 생성자 제약 조건

이때 B 유형에 대해 매개변수화된 생성자를 작성했기 때문에 시스템이 B 유형에 대해 매개변수 없는 생성자를 자동으로 생성하는 것을 방지합니다. 그러나 B 유형에 매개변수 없는 생성자를 추가하면, 개체 d의 인스턴스화는 오류를 보고하지 않습니다. B 유형은 다음과 같이 정의됩니다.

클래스 B

{

공개 B()

{ }

공개 B(int i)

{ }

     }

값 유형/참조 유형:

public struct A { }

public class B { }



public class C ) >
C c2 = new C();

컴파일 시 c2 객체에서 오류가 발생했습니다. 'B' 유형은 null을 허용하지 않는 값 유형이어야 합니다. 일반 유형 또는 'C' 메소드에서 매개변수 'T'로 사용하십시오.



요약:

1. C#의 일반 기능은 CLR에서 지원됩니다. 런타임에 C++에서 지원하는 정적 템플릿과 다르며, 컴파일러 수준에서 "삭제 방법"을 사용하여 Java에서 지원하는 간단한 제네릭과도 다릅니다.

2. C#의 일반 지원에는 클래스, 구조체, 인터페이스, 대리자 및 메서드 멤버의 네 가지 일반 유형이 포함됩니다.

3. C#의 제네릭은 "기본 클래스, 인터페이스, 생성자, 값 유형/참조 유형"의 제약 조건을 사용하여 유형 매개 변수에 대한 "명시적 제약 조건"을 구현합니다. 서명 기반 암시적 템플릿은 지원하지 않습니다. 제약.

위 내용은 C# 제네릭 프로그래밍 내용입니다. 더 많은 관련 내용은 PHP 중국어 홈페이지(www.php.cn)를 참고해주세요!



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