C#은 엄격한 형식의 언어입니다. 모든 변수와 상수에는 값으로 계산되는 모든 식과 마찬가지로 형식이 있습니다. 모든 메서드 선언은 각 입력 매개 변수 및 반환 값에 대한 이름, 형식 및 종류(값, 참조 또는 출력)를 지정합니다. .NET 클래스 라이브러리는 다양한 구문을 나타내는 기본 제공 숫자 형식 및 복합 형식을 정의합니다. 여기에는 파일 시스템, 네트워크 연결, 개체 컬렉션 및 배열 및 날짜가 포함됩니다. 일반적인 C# 프로그램은 클래스 라이브러리의 형식과 프로그램의 문제 도메인과 관련된 개념을 모델링하는 사용자 정의 형식을 사용합니다.
형식에 저장된 정보에는 다음 항목이 포함될 수 있습니다.
- 형식의 변수에 필요한 스토리지 공간입니다.
- 나타낼 수 있는 최대값 및 최소값입니다.
- 포함된 멤버(메서드, 필드, 이벤트 등)입니다.
- 상속되는 기본 형식입니다.
- 그것이 구현하는 인터페이스입니다.
- 허용되는 작업입니다.
컴파일러는 형식 정보를 사용하여 코드에서 수행되는 모든 작업이 형식이 안전한지 확인합니다. 예를 들어 형식 int
의 변수를 선언하는 경우 컴파일러를 사용하면 변수를 더하고 빼기 작업을 사용할 수 있습니다. 형식 bool
변수에 대해 동일한 작업을 수행하려고 하면 다음 예제와 같이 컴파일러가 오류를 생성합니다.
int a = 5;
int b = a + 2; //OK
bool test = true;
// Error. Operator '+' cannot be applied to operands of type 'int' and 'bool'.
int c = a + test;
비고
C 및 C++ 개발자는 C#에서 bool
를 int
로 변환할 수 없음을 주의하십시오.
컴파일러는 형식 정보를 실행 파일에 메타데이터로 포함합니다. CLR(공용 언어 런타임)은 런타임에 해당 메타데이터를 사용하여 메모리를 할당하고 회수할 때 형식 안전을 추가로 보장합니다.
변수 선언에서 형식 지정
프로그램에서 변수 또는 상수를 선언하는 경우 해당 형식을 지정하거나 키워드를 var
사용하여 컴파일러가 형식을 유추할 수 있도록 해야 합니다. 다음 예제에서는 기본 제공 숫자 형식과 복잡한 사용자 정의 형식을 모두 사용하는 일부 변수 선언을 보여 줍니다.
// Declaration only:
float temperature;
string name;
MyClass myClass;
// Declaration with initializers (four examples):
char firstLetter = 'C';
var limit = 3;
int[] source = [0, 1, 2, 3, 4, 5];
var query = from item in source
where item <= limit
select item;
메서드 매개 변수 및 반환 값의 형식은 메서드 선언에 지정됩니다. 다음 서명은 int
를 입력 인수로 필요로 하고 문자열을 반환하는 메서드를 보여줍니다.
public string GetName(int ID)
{
if (ID < names.Length)
return names[ID];
else
return String.Empty;
}
private string[] names = ["Spencer", "Sally", "Doug"];
변수를 선언한 후에는 새 형식으로 다시 묶을 수 없으며 선언된 형식과 호환되지 않는 값을 할당할 수 없습니다. 예를 들어, int
을 선언하고 나서 true
의 부울 값을 할당할 수 없습니다. 그러나 값이 새 변수에 할당되거나 메서드 인수로 전달되는 경우와 같이 다른 형식으로 변환할 수 있습니다. 데이터 손실을 유발하지 않는 형식 변환 은 컴파일러에서 자동으로 수행됩니다. 데이터 손실을 일으킬 수 있는 변환에는 소스 코드의 캐스트 가 필요합니다.
자세한 내용은 캐스팅 및 형식 변환을 참조하세요.
기본 제공 형식
C#은 기본 제공 형식의 표준 집합을 제공합니다. 정수, 부동 소수점 값, 부울 식, 텍스트 문자, 10진수 값 및 기타 데이터 형식을 나타냅니다. 기본 제공 string
및 object
형식도 있습니다. 이러한 형식은 모든 C# 프로그램에서 사용할 수 있습니다. 기본 제공 형식의 전체 목록은 기본 제공 형식을 참조하세요.
사용자 지정 형식
struct
, class
, interface
, enum
및 record
구문을 사용하여 고유한 사용자 지정 형식을 만듭니다. .NET 클래스 라이브러리 자체는 사용자 고유의 애플리케이션에서 사용할 수 있는 사용자 지정 형식의 컬렉션입니다. 기본적으로 클래스 라이브러리에서 가장 자주 사용되는 형식은 모든 C# 프로그램에서 사용할 수 있습니다. 다른 항목은 프로젝트 참조를 정의하는 어셈블리에 명시적으로 추가하는 경우에만 사용할 수 있습니다. 컴파일러에 어셈블리에 대한 참조가 있으면 소스 코드에서 해당 어셈블리에 선언된 형식의 변수(및 상수)를 선언할 수 있습니다. 자세한 내용은 .NET 클래스 라이브러리를 참조하세요.
형식을 정의할 때 가장 먼저 내리는 결정 중 하나는 형식에 사용할 구문을 결정하는 것입니다. 다음 목록은 초기 결정을 내리는 데 도움이 됩니다. 선택 항목에는 겹침이 있습니다. 대부분의 시나리오에서 둘 이상의 옵션이 적절한 선택입니다.
- 데이터 스토리지 크기가 64바이트 이하인 경우 또는
struct
record struct
을 선택합니다. - 형식이 불변인 경우, 또는 소멸이 없는 변경을 원하는 경우,
struct
또는record struct
을 선택합니다. - 일치하는 값 의미 체계가 필요한 경우,
record class
또는record struct
을 선택하십시오. - 형식이 동작이 아닌 데이터를 저장하는 데 주로 사용되는 경우 선택
record class
하거나record struct
선택합니다. - 형식이 상속 계층 구조의 일부인 경우,
record class
또는class
중 하나를 선택합니다. - 형식이 다형성을 사용하는 경우
class
을 선택하십시오. - 기본 용도가 동작인 경우 .를
class
선택합니다.
공용 형식 시스템
.NET의 형식 시스템에 대한 두 가지 기본 사항을 이해하는 것이 중요합니다.
- 상속 원칙을 지원합니다. 형식은 기본 형식이라고 하는 다른 형식에서 파생할 수 있습니다. 파생 형식은 메서드, 속성 및 기본 형식의 다른 멤버를 상속합니다(일부 제한 사항 포함). 기본 형식은 다른 형식에서 파생될 수 있습니다. 이 경우 파생된 형식은 상속 계층 구조에서 두 기본 형식의 멤버를 상속합니다. (C# 키워드: System.Int32)와 같은
int
기본 제공 숫자 형식을 비롯한 모든 형식은 System.Object 궁극적으로 단일 기본 형식(C# 키워드:object
)에서 파생됩니다. 이 통합 형식 계층을 CTS( 공용 형식 시스템 )라고 합니다. C#의 상속에 대한 자세한 내용은 상속을 참조 하세요. - CTS의 각 형식은 값 형식 또는 참조 형식으로 정의됩니다. 이러한 형식에는 .NET 클래스 라이브러리의 모든 사용자 지정 형식과 사용자 정의 형식도 포함됩니다. 키워드를 사용하여
struct
정의하는 형식은 값 형식이며 모든 기본 제공 숫자 형식은 다음과 같습니다structs
.class
또는record
키워드를 사용하여 정의한 형식은 참조 형식입니다. 참조 형식 및 값 형식에는 컴파일 시간 규칙이 다르고 런타임 동작이 다릅니다.
다음 그림에서는 CTS의 값 형식과 참조 형식 간의 관계를 보여 줍니다.
비고
가장 일반적으로 사용되는 형식이 모두 네임스페이스에 System 구성되어 있음을 알 수 있습니다. 그러나 형식이 포함된 네임스페이스는 값 형식인지 참조 형식인지와 관계가 없습니다.
클래스와 구조체는 .NET에서 공통 형식 시스템의 기본 구문 중 두 가지입니다. 각각은 기본적으로 논리 단위로 함께 속하는 데이터 및 동작 집합을 캡슐화하는 데이터 구조입니다. 데이터 및 동작은 클래스, 구조체 또는 레코드의 멤버 입니다. 멤버는 이 문서의 뒷부분에 나열된 대로 메서드, 속성, 이벤트 등을 포함합니다.
클래스, 구조체 또는 레코드 선언은 런타임에 인스턴스 또는 개체를 만드는 데 사용되는 청사진과 같습니다. 클래스, 구조체 또는 레코드의 이름으로 Person
를 정의하는 경우, 형식 이름은 Person
입니다.
p
형식의 변수 Person
선언하고 초기화하는 경우 p
Person
개체 또는 인스턴스라고 합니다. 동일한 Person
형식의 여러 인스턴스를 만들 수 있으며 각 인스턴스의 속성과 필드에 서로 다른 값을 가질 수 있습니다.
클래스는 참조 형식입니다. 형식의 개체를 만들 때 개체가 할당된 변수는 해당 메모리에 대한 참조만 보유합니다. 개체 참조가 새 변수에 할당되면 새 변수는 원래 개체를 참조합니다. 한 변수를 통해 변경된 내용은 모두 동일한 데이터를 참조하기 때문에 다른 변수에 반영됩니다.
구조체는 값 형식입니다. 구조체를 만들 때 구조체가 할당되는 변수는 구조체의 실제 데이터를 보유합니다. 구조체가 새 변수에 할당되면 복사됩니다. 따라서 새 변수와 원래 변수에는 동일한 데이터의 두 개의 개별 복사본이 포함됩니다. 한 복사본에 대한 변경 내용은 다른 복사본에 영향을 주지 않습니다.
레코드 형식은 참조 형식(record class
) 또는 값 형식(record struct
)일 수 있습니다. 레코드 형식에는 값 같음을 지원하는 메서드가 포함되어 있습니다.
일반적으로 클래스는 더 복잡한 동작을 모델링하는 데 사용됩니다. 클래스는 일반적으로 클래스 개체를 만든 후 수정할 데이터를 저장합니다. 구조체는 작은 데이터 구조에 가장 적합합니다. 구조체는 일반적으로 구조체를 만든 후 수정할 수 없는 데이터를 저장합니다. 레코드 형식은 추가 컴파일러 합성 멤버가 있는 데이터 구조입니다. 레코드는 일반적으로 개체를 만든 후 수정할 수 없는 데이터를 저장합니다.
값 형식
값 형식은 System.ValueType에서 파생되며, System.ValueType는 에서 파생됩니다. 파생 System.ValueType 되는 형식은 CLR에서 특수한 동작을 갖습니다. 값 형식 변수에는 해당 값이 직접 포함됩니다. 구조체의 메모리는 변수가 선언된 컨텍스트에서 인라인으로 할당됩니다. 값 형식 변수에 대한 별도의 힙 할당 또는 가비지 수집 오버헤드는 없습니다. 값 형식으로서 record struct
형식을 선언하고 레코드에 대한 합성 멤버를 포함할 수 있습니다.
값 형식에는 두 가지 범주가 있습니다 struct
enum
.
기본 제공 숫자 형식은 구조체이며 액세스할 수 있는 필드와 메서드가 있습니다.
// constant field on type byte.
byte b = byte.MaxValue;
그러나 단순 비 집계 형식인 것처럼 선언하고 값을 할당합니다.
byte num = 0xA;
int i = 5;
char c = 'Z';
값 형식은 봉인된입니다. 값 형식에서 형식을 파생시킬 수 없습니다(예: System.Int32). 사용자 정의 클래스 또는 구조체로부터 구조체는 상속받을 수 없으며, 구조체는 System.ValueType에서만 상속받을 수 있습니다. 그러나 구조체는 하나 이상의 인터페이스를 구현할 수 있습니다. 구조체 형식을 구현하는 모든 인터페이스 형식으로 캐스팅할 수 있습니다. 이 캐스트는 boxing 연산을 사용하여 구조체를 관리 힙의 참조 형식 개체로 래핑합니다. Boxing 작업은 값 형식을 System.Object 또는 인터페이스 형식으로 사용되는 메서드에 입력 매개 변수로 전달할 때 발생합니다. 자세한 내용은 Boxing 및 Unboxing을 참조하세요.
구조체 키워드를 사용하여 고유한 사용자 지정 값 형식을 만듭니다. 일반적으로 구조체는 다음 예제와 같이 작은 관련 변수 집합에 대한 컨테이너로 사용됩니다.
public struct Coords
{
public int x, y;
public Coords(int p1, int p2)
{
x = p1;
y = p2;
}
}
구조체에 대한 자세한 내용은 구조체 형식을 참조하세요. 값 형식에 대한 자세한 내용은 값 형식을 참조하세요.
값 형식의 다른 범주는 enum
. 열거형은 명명된 정수 상수 집합을 정의합니다. 예를 들어 .NET 클래스 라이브러리의 System.IO.FileMode 열거형에는 파일을 여는 방법을 지정하는 명명된 상수 정수 집합이 포함됩니다. 다음 예제와 같이 정의되어 있습니다.
public enum FileMode
{
CreateNew = 1,
Create = 2,
Open = 3,
OpenOrCreate = 4,
Truncate = 5,
Append = 6,
}
System.IO.FileMode.Create 상수의 값은 2입니다. 그러나 이 이름은 소스 코드를 읽는 사용자에게 훨씬 더 의미가 있으며, 이러한 이유로 상수 리터럴 번호 대신 열거형을 사용하는 것이 좋습니다. 자세한 내용은 System.IO.FileMode를 참조하세요.
모든 열거형은 System.Enum로부터 상속받으며, System.ValueType로부터 상속받습니다. 구조체에 적용되는 모든 규칙은 열거형에도 적용됩니다. 열거형에 대한 자세한 내용은 열거형 형식을 참조하세요.
참조 형식
class
, record
, delegate
, 배열 또는 interface
로 정의된 형식은 reference type
입니다.
reference type
형식의 변수를 선언하면, 인스턴스를 해당 형식으로 할당하거나 null
연산자를 사용하여 인스턴스를 생성하기 전까지 변수는 값 new
를 포함합니다. 클래스의 생성 및 할당은 다음 예제에서 설명합니다.
MyClass myClass = new MyClass();
MyClass myClass2 = myClass;
interface
는 new
연산자를 사용하여 직접 인스턴스화할 수 없습니다. 대신 인터페이스를 구현하는 클래스의 인스턴스를 만들고 할당합니다. 다음 예제를 고려하세요.
MyClass myClass = new MyClass();
// Declare and assign using an existing value.
IMyInterface myInterface = myClass;
// Or create and assign a value in a single statement.
IMyInterface myInterface2 = new MyClass();
개체를 만들면 메모리가 관리되는 힙에 할당됩니다. 변수는 개체의 위치에 대한 참조만 보유합니다. 관리되는 힙의 형식은 할당될 때와 회수될 때 모두 오버헤드가 필요합니다. 가비지 수집 은 재사용을 수행하는 CLR의 자동 메모리 관리 기능입니다. 그러나 가비지 수집은 고도로 최적화되어 있으며 대부분의 시나리오에서는 성능 문제가 발생하지 않습니다. 가비지 수집에 대한 자세한 내용은 자동 메모리 관리를 참조하세요.
모든 배열은 해당 요소가 값 형식인 경우에도 참조 형식입니다. 배열은 System.Array 클래스에서 암시적으로 파생됩니다. 다음 예제와 같이 C#에서 제공하는 간소화된 구문으로 선언하고 사용합니다.
// Declare and initialize an array of integers.
int[] nums = [1, 2, 3, 4, 5];
// Access an instance property of System.Array.
int len = nums.Length;
참조 형식은 상속을 완벽하게 지원합니다. 클래스를 만들 때 sealed로 정의되지 않은 다른 인터페이스 또는 클래스에서 상속할 수 있습니다. 다른 클래스는 사용자의 클래스에서 상속받고 가상 메서드를 재정의할 수 있습니다. 고유한 클래스를 만드는 방법에 대한 자세한 내용은 클래스, 구조체 및 레코드를 참조하세요. 상속 및 가상 메서드에 대한 자세한 내용은 상속을 참조 하세요.
리터럴 값의 유형
C#에서 리터럴 값은 컴파일러에서 형식을 받습니다. 숫자 끝에 문자를 추가하여 숫자 리터럴을 입력하는 방법을 지정할 수 있습니다. 예를 들어 값을 4.56
처리 float
하도록 지정하려면 숫자 4.56f
앞에 "f" 또는 "F"를 추가합니다. 문자가 추가되지 않으면 컴파일러는 리터럴의 형식을 유추합니다. 문자 접미사로 지정할 수 있는 형식에 대한 자세한 내용은 정수 숫자 형식 및 부동 소수점 숫자 형식을 참조하세요.
리터럴은 형식화되고 모든 형식은 궁극적으로 System.Object파생되므로 다음 코드와 같은 코드를 작성하고 컴파일할 수 있습니다.
string s = "The answer is " + 5.ToString();
// Outputs: "The answer is 5"
Console.WriteLine(s);
Type type = 12345.GetType();
// Outputs: "System.Int32"
Console.WriteLine(type);
제네릭 형식
형식은 실제 형식(구체적인 형식)의 자리 표시자 역할을 하는 하나 이상의 형식 매개 변수 를 사용하여 선언할 수 있습니다. 클라이언트 코드는 형식의 인스턴스를 만들 때 구체적인 형식을 제공합니다. 이러한 형식을 제네릭 형식이라고 합니다. 예를 들어 .NET 형식 System.Collections.Generic.List<T> 에는 규칙에 따라 이름이 T
지정된 하나의 형식 매개 변수가 있습니다. 형식의 인스턴스를 만들 때 목록에 포함된 개체의 형식을 지정합니다. 예를 들면 다음과 같습니다 string
.
List<string> stringList = new List<string>();
stringList.Add("String example");
// compile time error adding a type other than a string:
stringList.Add(4);
형식 매개 변수를 사용하면 각 요소를 개체로 변환하지 않고도 동일한 클래스를 다시 사용하여 모든 형식의 요소를 보유할 수 있습니다. 제네릭 컬렉션 클래스는 컴파일러가 컬렉션 요소의 특정 형식을 알고 있으며, 예를 들어 이전 예제의 개체에 정 수를 추가하려고 하면 컴파일 시간에 오류가 발생할 수 있기 때문에 stringList
의 컬렉션이라고 합니다. 자세한 내용은 제네릭을 참조하세요.
암시적 형식, 무명 형식 및 nullable 값 형식
키워드를 사용하여 지역 변수(클래스 멤버는 아님)를 암시적으로 입력할 var
수 있습니다. 변수는 컴파일 시간에 형식을 수신하지만 형식은 컴파일러에서 제공합니다. 자세한 내용은 암시적으로 형식화된 지역 변수를 참조하세요.
메서드 경계 외부를 저장하거나 전달하지 않으려는 간단한 관련 값 집합에 대해 명명된 형식을 만드는 것이 불편할 수 있습니다. 이 목적을 위해 익명 형식 을 만들 수 있습니다. 자세한 내용은 익명 형식을 참조하세요.
일반 값 형식에는 값 null
이 있을 수 없습니다. 그러나 형식 뒤에 를 추가하여 ?
을 만들 수 있습니다. 예를 들어 int?
int
값 null
도 가질 수 있는 형식입니다. Nullable 값 형식은 제네릭 구조체 형식 System.Nullable<T>의 인스턴스입니다. Nullable 값 형식은 숫자 값이 null
일 수 있는 데이터베이스에 데이터를 주고받을 때 특히 유용합니다. 자세한 내용은 Nullable 값 형식을 참조하세요.
컴파일 시간 형식 및 런타임 형식
변수는 컴파일 시간 및 런타임 형식이 다를 수 있습니다. 컴파일 시간 형식은 소스 코드에서 변수의 선언되거나 유추된 형식입니다. 런타임 형식은 해당 변수에서 참조하는 인스턴스의 형식입니다. 이러한 두 형식은 다음 예제와 같이 동일한 경우가 많습니다.
string message = "This is a string of characters";
다른 경우에는 다음 두 예제와 같이 컴파일 시간 형식이 다릅니다.
object anotherMessage = "This is another string of characters";
IEnumerable<char> someCharacters = "abcdefghijklmnopqrstuvwxyz";
앞의 두 예제에서 런타임 형식은 .입니다 string
. 컴파일 시간 형식은 object
첫 번째 줄과 IEnumerable<char>
두 번째 줄에 있습니다.
변수에 대해 두 형식이 다른 경우 컴파일 시간 형식과 런타임 형식이 적용되는 시기를 이해하는 것이 중요합니다. 컴파일 시간 형식은 컴파일러에서 수행한 모든 작업을 결정합니다. 이러한 컴파일러 작업에는 메서드 호출 확인, 오버로드 확인 및 사용 가능한 암시적 및 명시적 캐스트가 포함됩니다. 실행 시간 유형은 실행 시간에 해결되는 모든 작업을 결정합니다. 이러한 런타임 작업에는 가상 메서드 호출의 디스패치, is
및 switch
식의 평가, 기타 형식 테스트 API가 포함됩니다. 코드가 형식과 상호 작용하는 방식을 더 잘 이해하려면 어떤 작업이 어떤 형식에 적용되는지 인식합니다.
관련 섹션
자세한 내용은 다음 문서를 참조하세요.
C# 언어 사양
자세한 내용은 C# 언어 사양을 참조하세요. 언어 사양은 C# 구문 및 사용의 최종 소스입니다.
.NET