C# 일반 프로그래밍
Dec 21, 2016 pm 02:47 PM제네릭: 매개변수화된 유형을 사용하여 동일한 코드에서 여러 데이터 유형을 작동합니다. 유연한 재사용을 위해 "매개변수화된 유형"을 사용하여 유형을 추상화하세요.
예제 코드:
class PRogram
{
static void Main(string[] args)
{
int obj = 2;
Test
Console.WriteLine("int:" + test.obj);
string obj2 = "hello world";
Test
Console.WriteLine("String:" + test 1 .obj);
Console.Read();
}
}
클래스 테스트<T>
{
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<int32>::.ctor(!0)
IL_0009: stloc.1
IL_000a: " ldstr "int:"
IL_000f: ldloc.1
IL_0010: ldfld !0 class CSharpStudy1.Test`1<int32>::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<string>::.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<!T> ::obj
IL_000f: nop
IL_0010: ret
} // 메서드 끝 Test`1::.ctor
1. 컴파일 라운드 동안 컴파일러는 IL 코드의 "일반 버전"과 Test<T> 유형에 대한 메타데이터만 생성합니다. 이는 일반 코드를 인스턴스화하지 않으며 T는 중간에 자리 표시자 역할만 합니다. 예: 테스트 유형 메타데이터에 표시된 <!T>
2. JIT 컴파일 중에 JIT 컴파일러가 처음으로 Test<int>를 발견하면 "일반 버전"이 int로 대체됩니다. IL 코드 및 메타데이터의 T - 일반 유형의 인스턴스화. 예: Main 함수에 표시된 <int>
3. CLR은 유형 매개변수가 "참조 유형"인 모든 일반 유형에 대해 동일한 코드를 생성합니다. 각각에 대해 CLR이 별도의 코드를 생성하는 다른 "값 유형"입니다. 참조 유형 제네릭을 인스턴스화할 때는 메모리에 할당되는 크기가 동일하지만 값 유형을 인스턴스화할 때는 메모리에 할당되는 크기가 다르기 때문입니다.
C# 일반 기능:
1. 인스턴스화된 제네릭 유형의 매개변수가 동일한 경우 JIT 편집기는 해당 유형을 재사용하므로 C#의 동적 제네릭은 유형 기능은 C++ 정적 템플릿으로 인해 발생할 수 있는 코드 팽창 문제를 방지합니다.
2. C# 제네릭 유형은 풍부한 메타데이터를 전달하므로 C#의 제네릭 유형은 강력한 리플렉션 기술에 적용될 수 있습니다.
3. C#의 제네릭은 "기본 클래스, 인터페이스, 생성자, 값 유형/참조 유형"의 제약 조건 메서드를 사용하여 유형 매개 변수에 대한 "명시적 제약 조건"을 구현합니다. 이는 유형 안전성뿐 아니라 손실도 향상시킵니다. "서명" 암시적 제약 조건을 기반으로 하는 C++ 템플릿의 높은 유연성
C# 일반 상속:
C# 일반 유형을 별도로 선언할 수 있는 것 외에도( 클래스 및 구조), 기본 클래스에 제네릭 유형의 선언을 포함할 수도 있습니다. 그러나 기본 클래스가 일반 클래스인 경우 해당 유형은 하위 클래스(일반 유형이기도 함)에서 선언된 유형 매개변수에서 인스턴스화되거나 파생됩니다.
class C<U,V> 🎜>
클래스 D:C
클래스 E:C
클래스 F:C
class G:C<U,V> //Illegal
E 유형은 위에서 언급한 하위 클래스에서 파생된 C 유형에 대해 U 및 V를 제공합니다.
F 유형은 C
G 유형은 제네릭이 아니고 C이기 때문에 불법입니다. Generics이므로 G는 C에 일반 인스턴스화를 제공할 수 없습니다
제네릭 유형의 멤버:
제네릭 유형의 멤버는 제네릭 유형 선언에서 유형 매개변수를 사용할 수 있습니다. 그러나 형식 매개 변수에 제약 조건이 없으면 해당 형식의 System.Object에서 상속된 공용 멤버만 사용할 수 있습니다. 아래와 같이:
일반 인터페이스:
일반 인터페이스의 유형 매개변수는 인스턴스화되거나 구현 클래스에 의해 선언된 유형 매개변수에서 파생됩니다
일반 대리자:
일반 대리자는 대리자 반환 값 및 매개 변수에 대한 매개 변수 유형 적용을 지원합니다. 이러한 매개 변수 유형에는 법적 제약 조건이 적용될 수도 있습니다
대리자 bool MyDelegate<T>(T 값);
class MyClass
{
static bool F(int i){...}
static bool G(string s){...}
static void Main()
{
MyDelegate<string> 🎜> MyDelegate<int> p1 = new MyDelegate<int>(F);
}
}
일반 메서드:
1. C# 일반 메커니즘은 "메서드 선언에 형식 매개변수 포함", 즉 일반 메서드만 지원합니다.
2. C# 제네릭 메커니즘은 메서드를 제외한 다른 멤버(속성, 이벤트, 인덱서, 생성자, 소멸자 포함) 선언에 형식 매개 변수를 포함하는 것을 지원하지 않지만 이러한 멤버 자체는 제네릭에 포함될 수 있습니다. 일반 유형의 유형 매개변수를 입력하고 사용하십시오.
3. 제네릭 메소드는 제네릭 유형과 비제네릭 유형 모두에 포함될 수 있습니다.
일반 메서드 선언: 다음과 같습니다
public static int FunctionName<T>(T 값){...}
일반 메소드 오버로딩:
public void Function1
public void Function1(U a);
이렇게 하면 됩니다. 제네릭 메서드의 오버로드를 구성할 수 없습니다. 컴파일러는 제네릭 유형 T와 U가 다른지 여부를 확인할 수 없기 때문에 두 메서드가 다른지 여부를 확인할 수 없습니다.
public void Function1<T>(int x);
public void Function1(int x);
이는 오버로드를 구성할 수 있습니다
public void Function1<T>(T t) where T:A;
public void Function1<T>(T t) where T:B;
이것은 일반 메소드의 오버로딩을 구성할 수 없습니다. 컴파일러는 제약 조건의 A와 B가 다른지 여부를 확인할 수 없기 때문에 두 메서드가 다른지 여부를 확인할 수 없습니다.
일반 메서드 재작성:
재작성 중 프로세스에서는 추상 클래스의 추상 메서드 제약 조건이 기본적으로 상속됩니다. 다음과 같습니다:
추상 클래스 Base
{
public abstract T F<T,U>(T t,U u) where U:T;
공개 요약 T G<T>(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<S, T>
where S : A
where T : B
{
공개 C(S s,T t)
{
//S의 변수는 Func1 메소드를 호출할 수 있습니다
s.Func1() >
}
}
인터페이스 제약 조건:
인터페이스 IA< ;T>
{
T Func1()
}
인터페이스 IB
{
void Func2();
}
인터페이스 IC<T>
{
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> 여기서 T : new()
{
T t;
public C()
t = 새로운 T();
}
}
클래스 D
{
공개 무효 Func()
C<B> d = 새로운 C<B>();
}
}
d 객체를 컴파일할 때 오류가 발생합니다. 제네릭 유형 또는 메서드 C<T>
에서 매개 변수 'T'로 사용하려면 유형 B에 매개 변수가 없는 공용 생성자가 있어야 합니다. 참고: C#에서는 이제 no-만 지원합니다. 매개변수 생성자 제약 조건
이때 B 유형에 대해 매개변수화된 생성자를 작성했기 때문에 시스템이 B 유형에 대해 매개변수 없는 생성자를 자동으로 생성하는 것을 방지합니다. 그러나 B 유형에 매개변수 없는 생성자를 추가하면, 개체 d의 인스턴스화는 오류를 보고하지 않습니다. B 유형은 다음과 같이 정의됩니다.
클래스 B
{
공개 B()
{ }
공개 B(int i)
{ }
}
값 유형/참조 유형:
public struct A { }
public class B { }
public class C<T> ) >
C<B> c2 = new C<B>();
컴파일 시 c2 객체에서 오류가 발생했습니다. 'B' 유형은 null을 허용하지 않는 값 유형이어야 합니다. 일반 유형 또는 'C<T>' 메소드에서 매개변수 'T'로 사용하십시오.
요약:
1. C#의 일반 기능은 CLR에서 지원됩니다. 런타임에 C++에서 지원하는 정적 템플릿과 다르며, 컴파일러 수준에서 "삭제 방법"을 사용하여 Java에서 지원하는 간단한 제네릭과도 다릅니다.
2. C#의 일반 지원에는 클래스, 구조체, 인터페이스, 대리자 및 메서드 멤버의 네 가지 일반 유형이 포함됩니다.
3. C#의 제네릭은 "기본 클래스, 인터페이스, 생성자, 값 유형/참조 유형"의 제약 조건을 사용하여 유형 매개 변수에 대한 "명시적 제약 조건"을 구현합니다. 서명 기반 암시적 템플릿은 지원하지 않습니다. 제약.
위 내용은 C# 제네릭 프로그래밍 내용입니다. 더 많은 관련 내용은 PHP 중국어 홈페이지(www.php.cn)를 참고해주세요!

인기 기사

인기 기사

뜨거운 기사 태그

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제









