형식(C# 프로그래밍 가이드)Types (C# Programming Guide)

형식, 변수 및 값Types, Variables, and Values

C#은 강력한 형식의 언어입니다.C# is a strongly-typed language. 모든 변수 및 상수에는 값으로 계산되는 모든 식을 실행하는 형식이 있습니다.Every variable and constant has a type, as does every expression that evaluates to a value. 모든 메서드 시그니처는 각 입력 매개 변수 및 반환 값의 형식을 지정합니다.Every method signature specifies a type for each input parameter and for the return value. .NET 클래스 라이브러리는 기본 제공 숫자 형식 집합 및 파일 시스템, 네트워크 연결, 컬렉션, 개체 배열, 날짜 등의 다양한 논리 구문을 나타내는 더 복잡한 형식을 정의합니다.The .NET class library defines a set of built-in numeric types as well as more complex types that represent a wide variety of logical constructs, such as the file system, network connections, collections and arrays of objects, and dates. 일반 C# 프로그램에서는 클래스 라이브러리의 형식 및 프로그램의 문제 도메인에 관련된 개념을 모델링하는 사용자 정의 형식을 사용합니다.A typical C# program uses types from the class library as well as user-defined types that model the concepts that are specific to the program's problem domain.

형식에 저장된 정보에는 다음이 포함될 수 있습니다.The information stored in a type can include the following:

  • 형식 변수에 필요한 스토리지 공간.The storage space that a variable of the type requires.

  • 형식이 나타낼 수 있는 최대값 및 최소값.The maximum and minimum values that it can represent.

  • 형식에 포함되는 멤버(메서드, 필드, 이벤트 등).The members (methods, fields, events, and so on) that it contains.

  • 형식이 상속하는 기본 형식.The base type it inherits from.

  • 런타임에 변수에 대한 메모리가 할당될 위치.The location where the memory for variables will be allocated at run time.

  • 허용되는 작업 유형.The kinds of operations that are permitted.

컴파일러는 형식 정보를 사용하여 코드에서 수행되는 모든 작업이 형식이 안전한지 확인합니다.The compiler uses type information to make sure that all operations that are performed in your code are type safe. 예를 들어 int 형식의 변수를 선언할 경우 컴파일러를 통해 더하기 및 빼기 작업에서 변수를 사용할 수 있습니다.For example, if you declare a variable of type int, the compiler allows you to use the variable in addition and subtraction operations. bool 형식의 변수에 대해 같은 작업을 수행하려고 하면 컴파일러는 다음 예제와 같이 오류를 생성합니다.If you try to perform those same operations on a variable of type bool, the compiler generates an error, as shown in the following example:

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#에서 boolint로 변환될 수 없음을 알고 있습니다.C and C++ developers, notice that in C#, bool is not convertible to int.

컴파일러는 형식 정보를 실행 파일에 메타데이터로 포함합니다.The compiler embeds the type information into the executable file as metadata. CLR(공용 언어 런타임)는 런타임에 이 메타데이터를 사용하여 메모리를 할당 및 회수할 때 형식 안정성을 추가로 보장합니다.The common language runtime (CLR) uses that metadata at run time to further guarantee type safety when it allocates and reclaims memory.

변수 선언에서 형식 지정Specifying Types in Variable Declarations

프로그램에서 변수나 상수를 선언할 때 컴파일러가 형식을 유추하게 하려면 형식을 지정하거나 var 키워드를 사용해야 합니다.When you declare a variable or constant in a program, you must either specify its type or use the var keyword to let the compiler infer the type. 다음 예제에서는 기본 제공 숫자 형식 및 복잡한 사용자 정의 형식을 둘 다 사용하는 일부 변수 선언을 보여 줍니다.The following example shows some variable declarations that use both built-in numeric types and complex user-defined types:

// 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;

메서드 매개 변수 및 반환 값의 형식은 메서드 시그니처에서 지정됩니다.The types of method parameters and return values are specified in the method signature. 다음 시그니처는 입력 인수로 int가 필요하고 문자열을 반환하는 메서드를 보여 줍니다.The following signature shows a method that requires an int as an input argument and returns a string:

public string GetName(int ID)
{
    if (ID < names.Length)
        return names[ID];
    else
        return String.Empty;
}
private string[] names = { "Spencer", "Sally", "Doug" };

변수가 선언된 후에는 새 형식으로 다시 선언될 수 없고 선언된 형식과 호환되지 않는 값이 할당될 수 없습니다.After a variable is declared, it cannot be re-declared with a new type, and it cannot be assigned a value that is not compatible with its declared type. 예를 들어 int를 선언하고 true의 부울 값을 여기에 할당할 수 있습니다.For example, you cannot declare an int and then assign it a Boolean value of true. 그러나 값은 새 변수에 할당되거나 메서드 인수로 전달될 경우 다른 형식으로 변환할 수 있습니다.However, values can be converted to other types, for example when they are assigned to new variables or passed as method arguments. 데이터 손실을 일으키지 않는 형식 변환은 컴파일러에서 자동으로 수행됩니다.A type conversion that does not cause data loss is performed automatically by the compiler. 데이터 손실을 일으킬 수 있는 변환의 경우 소스 코드에 캐스트가 있어야 합니다.A conversion that might cause data loss requires a cast in the source code.

자세한 내용은 캐스팅 및 형식 변환을 참조하세요.For more information, see Casting and Type Conversions.

기본 제공 형식Built-in Types

C#에서는 정수, 부동 소수점 값, 부울 식, 텍스트 문자, 10진수 값 및 기타 데이터 형식을 표현하는 기본 제공 숫자 형식의 표준 집합을 제공합니다.C# provides a standard set of built-in numeric types to represent integers, floating point values, Boolean expressions, text characters, decimal values, and other types of data. 이 밖에도 기본 제공 stringobject 형식이 있습니다.There are also built-in string and object types. 이러한 형식을 모든 C# 프로그램에서 사용할 수 있습니다.These are available for you to use in any C# program. 기본 제공 형식에 대한 자세한 내용은 기본 제공 형식에 대한 참조 테이블을 참조하세요.For more information about the built-in types, see Reference Tables for built-in Types.

사용자 지정 형식Custom Types

struct, class, interfaceenum 구문을 사용하여 자체 사용자 지정 형식을 만듭니다.You use the struct, class, interface, and enum constructs to create your own custom types. .NET 클래스 라이브러리 자체는 자체 애플리케이션에서 사용할 수 있는 Microsoft에서 제공되는 사용자 지정 형식의 컬렉션입니다.The .NET class library itself is a collection of custom types provided by Microsoft that you can use in your own applications. 기본적으로 클래스 라이브러리의 가장 자주 사용되는 형식을 모든 C# 프로그램에서 사용할 수 있습니다.By default, the most frequently used types in the class library are available in any C# program. 기타 형식은 정의되어 있는 어셈블리에 대한 프로젝트 참조를 명시적으로 추가할 경우에만 사용할 수 있습니다.Others become available only when you explicitly add a project reference to the assembly in which they are defined. 컴파일러에 어셈블리에 대한 참조가 포함된 후에는 소스 코드에서 해당 어셈블리에 선언된 형식의 변수(및 상수)를 선언할 수 있습니다.After the compiler has a reference to the assembly, you can declare variables (and constants) of the types declared in that assembly in source code. 자세한 내용은 .NET 클래스 라이브러리를 참조하세요.For more information, see .NET Class Library.

공용 형식 시스템.The Common Type System

.NET의 형식 시스템에 대한 다음과 같은 두 가지 기초 사항을 이해해야 합니다.It is important to understand two fundamental points about the type system in .NET:

  • 형식 시스템은 상속 원칙을 지원합니다.It supports the principle of inheritance. 형식은 기본 형식이라는 다른 형식에서 파생될 수 있습니다.Types can derive from other types, called base types. 파생 형식은 기본 형식의 메서드, 속성 및 기타 멤버를 상속합니다(몇 가지 제한 사항 있음).The derived type inherits (with some restrictions) the methods, properties, and other members of the base type. 기본 형식이 다른 형식에서 파생될 수도 있습니다. 이 경우 파생 형식은 상속 계층 구조에 있는 두 기본 형식의 멤버를 상속합니다.The base type can in turn derive from some other type, in which case the derived type inherits the members of both base types in its inheritance hierarchy. System.Int32(C# 키워드: int)와 같은 기본 제공 숫자 형식을 포함한 모든 형식은 기본적으로 단일 기본 형식 System.Object(C# 키워드: object)에서 파생됩니다.All types, including built-in numeric types such as System.Int32 (C# keyword: int), derive ultimately from a single base type, which is System.Object (C# keyword: object). 이 통합 형식 계층 구조를 CTS(공용 형식 시스템)라고 합니다.This unified type hierarchy is called the Common Type System (CTS). C#의 상속에 대한 자세한 내용은 상속을 참조하세요.For more information about inheritance in C#, see Inheritance.

  • CTS의 각 형식은 값 형식 또는 참조 형식으로 정의됩니다.Each type in the CTS is defined as either a value type or a reference type. 여기에는 .NET 클래스 라이브러리의 모든 사용자 지정 형식과 자체 사용자 정의 형식도 포함됩니다.This includes all custom types in the .NET class library and also your own user-defined types. struct를 사용하여 정의한 형식은 값 형식이고, 모든 기본 제공 숫자 형식은 structs입니다.Types that you define by using the struct keyword are value types; all the built-in numeric types are structs. class 키워드를 사용하여 정의한 형식은 참조 형식입니다.Types that you define by using the class keyword are reference types. 참조 형식과 값 형식의 컴파일 타임 규칙 및 런타임 동작은 서로 다릅니다.Reference types and value types have different compile-time rules, and different run-time behavior.

다음 그림에서는 CTS에서 값 형식과 참조 형식 간의 관계를 보여 줍니다.The following illustration shows the relationship between value types and reference types in the CTS.

다음 이미지에서는 CTS의 값 형식과 참조 형식을 보여줍니다.The following image shows value types and reference types in the CTS:

CTS 값 형식 및 참조 형식을 보여주는 스크린샷

참고

가장 일반적으로 사용되는 형식은 모두 System 네임스페이스에 구성되어 있다는 사실을 알 수 있습니다.You can see that the most commonly used types are all organized in the System namespace. 그러나 형식이 포함된 네임스페이스는 형식이 값 형식인지 또는 참조 형식인지와 관련이 없습니다.However, the namespace in which a type is contained has no relation to whether it is a value type or reference type.

값 형식Value Types

값 형식은 System.Object에서 파생되는 System.ValueType에서 파생됩니다.Value types derive from System.ValueType, which derives from System.Object. System.ValueType에서 파생되는 형식에는 CLR의 특수 동작이 있습니다.Types that derive from System.ValueType have special behavior in the CLR. 값 형식 변수에는 해당 값이 직접 포함되므로, 변수가 선언된 컨텍스트에 관계없이 메모리가 인라인으로 할당됩니다.Value type variables directly contain their values, which means that the memory is allocated inline in whatever context the variable is declared. 값 형식 변수에 대한 별도 힙 할당이나 가비지 수집 오버헤드는 없습니다.There is no separate heap allocation or garbage collection overhead for value-type variables.

값 형식에는 structenum의 두 가지 범주가 있습니다.There are two categories of value types: struct and enum.

기본 제공 숫자 형식은 구조체이며, 액세스할 수 있는 속성과 메서드가 있습니다.The built-in numeric types are structs, and they have properties and methods that you can access:

// Static method on type byte.
byte b = byte.MaxValue;

하지만 단순 비집계 형식처럼 값을 선언하고 변수에 할당합니다.But you declare and assign values to them as if they were simple non-aggregate types:

byte num = 0xA;
int i = 5;
char c = 'Z';

값 형식은 sealed이므로, 예를 들어 System.Int32에서 형식을 파생시킬 수 없으며 구조체는 System.ValueType에서만 상속할 수 있기 때문에 사용자 정의 클래스 또는 구조체에서 상속하는 구조체를 정의할 수 없습니다.Value types are sealed, which means, for example, that you cannot derive a type from System.Int32, and you cannot define a struct to inherit from any user-defined class or struct because a struct can only inherit from System.ValueType. 그러나 구조체는 하나 이상의 인터페이스를 구현할 수 있습니다.However, a struct can implement one or more interfaces. 구조체 형식을 구조체가 구현하는 인터페이스 형식으로 캐스트할 수 있습니다. 이 경우 boxing 작업은 관리되는 힙의 참조 형식 개체 내에 구조체를 래핑합니다.You can cast a struct type to any interface type that it implements; this causes a boxing operation to wrap the struct inside a reference type object on the managed heap. Boxing 작업은 System.Object 또는 인터페이스 형식을 입력 매개 변수로 사용하는 메서드에 값 형식을 전달할 때 발생합니다.Boxing operations occur when you pass a value type to a method that takes a System.Object or any interface type as an input parameter. 자세한 내용은 boxing 및 unboxing을 참조하세요.For more information, see Boxing and Unboxing.

struct 키워드를 사용하여 고유한 사용자 지정 값 형식을 만듭니다.You use the struct keyword to create your own custom value types. 일반적으로 구조체는 다음 예제와 같이 소규모 관련 변수 집합의 컨테이너로 사용됩니다.Typically, a struct is used as a container for a small set of related variables, as shown in the following example:

public struct Coords
{
    public int x, y;

    public Coords(int p1, int p2)
    {
        x = p1;
        y = p2;
    }
}

구조체에 대한 자세한 내용은 구조체를 참조하세요.For more information about structs, see Structs. .NET의 값 형식에 대한 자세한 내용은 값 형식을 참조하세요.For more information about value types in .NET, see Value Types.

값 형식의 다른 범주는 enum입니다.The other category of value types is enum. 열거형은 명명된 정수 상수 집합을 정의합니다.An enum defines a set of named integral constants. 예를 들어, .NET 클래스 라이브러리의 System.IO.FileMode 열거형에는 파일을 여는 방법을 지정하는 명명된 상수 정수 집합이 포함됩니다.For example, the System.IO.FileMode enumeration in the .NET class library contains a set of named constant integers that specify how a file should be opened. 이 패턴은 다음 예제와 같이 정의됩니다.It is defined as shown in the following example:

public enum FileMode
{
    CreateNew = 1,
    Create = 2,
    Open = 3,
    OpenOrCreate = 4,
    Truncate = 5,
    Append = 6,
}

System.IO.FileMode.Create 상수 값은 2입니다.The System.IO.FileMode.Create constant has a value of 2. 그러나 이 이름은 소스 코드를 읽는 사람에게 훨씬 더 의미가 있습니다. 따라서 상수 리터럴 숫자 대신 열거형을 사용하는 것이 더 좋습니다.However, the name is much more meaningful for humans reading the source code, and for that reason it is better to use enumerations instead of constant literal numbers. 자세한 내용은 System.IO.FileMode을 참조하세요.For more information, see System.IO.FileMode.

모든 열거형은 System.ValueType에서 상속받는 System.Enum에서 상속됩니다.All enums inherit from System.Enum, which inherits from System.ValueType. 구조체에 적용되는 모든 규칙이 열거형에도 적용됩니다.All the rules that apply to structs also apply to enums. 열거형에 대한 자세한 내용은 열거형 형식을 참조하세요.For more information about enums, see Enumeration Types.

참조 형식Reference Types

클래스, 대리자, 배열 또는 인터페이스로 정의되는 형식은 참조 형식입니다.A type that is defined as a class, delegate, array, or interface is a reference type. 런타임에 참조 형식의 변수를 선언하면 new 연산자를 사용하여 개체를 명시적으로 만들거나 다음 예제와 같이 new를 사용하여 다른 곳에서 만들어진 개체를 할당할 때까지 변수에는 null 값이 포함됩니다.At run time, when you declare a variable of a reference type, the variable contains the value null until you explicitly create an object by using the new operator, or assign it an object that has been created elsewhere by using new, as shown in the following example:

MyClass mc = new MyClass();
MyClass mc2 = mc;

인터페이스는 구현하는 클래스 개체와 함께 초기화되어야 합니다.An interface must be initialized together with a class object that implements it. MyClassIMyInterface를 구현하는 경우 다음 예제와 같이 IMyInterface의 인스턴스를 만듭니다.If MyClass implements IMyInterface, you create an instance of IMyInterface as shown in the following example:

IMyInterface iface = new MyClass();

개체가 만들어지면 관리되는 힙에 메모리가 할당되고 변수에는 개체 위치에 대한 참조만 포함됩니다.When the object is created, the memory is allocated on the managed heap, and the variable holds only a reference to the location of the object. 관리되는 힙의 형식은 할당될 때, 그리고 가비지 수집이라는 CLR의 자동 메모리 관리 기능에 의해 회수될 때 오버헤드가 필요합니다.Types on the managed heap require overhead both when they are allocated and when they are reclaimed by the automatic memory management functionality of the CLR, which is known as garbage collection. 그러나 가비지 수집은 고도로 최적화되고 대부분 시나리오에서 성능 문제를 일으키지 않습니다.However, garbage collection is also highly optimized, and in most scenarios it does not create a performance issue. 가비지 수집에 대한 자세한 내용은 자동 메모리 관리를 참조하세요.For more information about garbage collection, see Automatic Memory Management.

모든 배열은 해당 요소가 값 형식이더라도 참조 형식입니다.All arrays are reference types, even if their elements are value types. 배열은 System.Array 클래스에서 암시적으로 파생되지만 다음 예제와 같이 C#에서 제공하는 단순한 구문을 사용하여 배열을 선언하고 사용할 수 있습니다.Arrays implicitly derive from the System.Array class, but you declare and use them with the simplified syntax that is provided by C#, as shown in the following example:

// 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;

참조 형식은 상속을 완벽하게 지원합니다.Reference types fully support inheritance. 클래스를 만들 때 sealed로 정의되지 않은 기타 인터페이스 또는 클래스에서 상속될 수 있고 기타 클래스는 직접 만든 클래스에서 상속되고 가상 메서드를 재정의할 수 있습니다.When you create a class, you can inherit from any other interface or class that is not defined as sealed, and other classes can inherit from your class and override your virtual methods. 클래스를 직접 만드는 방법에 대한 자세한 내용은 클래스 및 구조체를 참조하세요.For more information about how to create your own classes, see Classes and Structs. 상속 및 가상 메서드에 대한 자세한 내용은 상속을 참조하세요.For more information about inheritance and virtual methods, see Inheritance.

리터럴 값 형식Types of Literal Values

C#에서는 리터럴 값이 컴파일러에서 형식을 받습니다.In C#, literal values receive a type from the compiler. 숫자의 끝에 문자를 추가하여 숫자 리터럴의 입력 방법을 지정할 수 있습니다.You can specify how a numeric literal should be typed by appending a letter to the end of the number. 예를 들어 값 4.56이 float로 처리되도록 지정하려면 숫자 뒤에 "f" 또는 "F"를 추가합니다(4.56f).For example, to specify that the value 4.56 should be treated as a float, append an "f" or "F" after the number: 4.56f. 문자를 추가하지 않으면 컴파일러가 리터럴의 형식을 유추합니다.If no letter is appended, the compiler will infer a type for the literal. 문자 접미사와 함께 지정할 수 있는 형식에 대한 자세한 내용은 값 형식에서 개별 형식의 참조 페이지를 참조하세요.For more information about which types can be specified with letter suffixes, see the reference pages for individual types in Value Types.

리터럴은 형식화되고 모든 형식이 궁극적으로 System.Object에서 파생되기 때문에 다음과 같은 코드를 작성하고 컴파일할 수 있습니다.Because literals are typed, and all types derive ultimately from System.Object, you can write and compile code such as the following:

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);

제네릭 형식Generic Types

클라이언트 코드가 형식의 인스턴스를 만들 때 제공하는 실제 형식(구체적 형식)에 대한 자리 표시자로 사용되는 하나 이상의 형식 매개 변수를 사용하여 형식을 선언할 수 있습니다.A type can be declared with one or more type parameters that serve as a placeholder for the actual type (the concrete type) that client code will provide when it creates an instance of the type. 해당 형식을 제네릭 형식이라고 합니다.Such types are called generic types. 예를 들어, .NET 형식 System.Collections.Generic.List<T>에는 변환을 통해 이름 T가 제공되는 하나의 형식 매개 변수가 있습니다. 형식의 인스턴스를 만들 때 목록에 포함될 개체의 형식(예: 문자열)을 지정합니다.For example, the .NET type System.Collections.Generic.List<T> has one type parameter that by convention is given the name T. When you create an instance of the type, you specify the type of the objects that the list will contain, for example, string:

List<string> stringList = new List<string>();
stringList.Add("String example");
// compile time error adding a type other than a string:
stringList.Add(4);

형식 매개 변수를 사용하면 각 요소를 개체로 변환할 필요 없이 같은 클래스를 재사용하여 요소 형식을 포함할 수 있습니다.The use of the type parameter makes it possible to reuse the same class to hold any type of element, without having to convert each element to object. 컴파일러는 컬렉션 요소의 특정 형식을 인식하며, 예를 들어 이전 예제에서 stringList 개체에 정수를 추가하려는 경우 컴파일 시간에 오류를 발생시킬 수 있기 때문에 제네릭 컬렉션 클래스를 강력한 형식의 컬렉션이라고 합니다.Generic collection classes are called strongly-typed collections because the compiler knows the specific type of the collection's elements and can raise an error at compile-time if, for example, you try to add an integer to the stringList object in the previous example. 자세한 내용은 제네릭을 참조하세요.For more information, see Generics.

암시적 형식, 무명 형식 및 Null 허용 형식Implicit Types, Anonymous Types, and Nullable Types

앞에서 설명한 대로 var 키워드를 사용하여 클래스 멤버가 아닌 로컬 변수를 암시적으로 형식화할 수 있습니다.As stated previously, you can implicitly type a local variable (but not class members) by using the var keyword. 이 변수는 컴파일 타임에 형식을 받지만 형식은 컴파일러에서 제공됩니다.The variable still receives a type at compile time, but the type is provided by the compiler. 자세한 내용은 암시적으로 형식화된 지역 변수를 참조하세요.For more information, see Implicitly Typed Local Variables.

경우에 따라 저장하거나 메서드 경계 외부로 전달할 의도가 없는 관련 값의 단순 집합에 대한 명명된 형식을 만드는 것은 불편합니다.In some cases, it is inconvenient to create a named type for simple sets of related values that you do not intend to store or pass outside method boundaries. 이 목적으로는 무명 형식을 만들 수 있습니다.You can create anonymous types for this purpose. 자세한 내용은 무명 형식을 참조하세요.For more information, see Anonymous Types.

일반적인 값 형식은 null 값을 가질 수 없습니다.Ordinary value types cannot have a value of null. 그러나 형식 뒤에 ?를 추가하면 null 허용 값 형식을However, you can create nullable value types by affixing a ? after the type. 예를 들어 int?null 값을 가질 수도 있는 int 형식입니다.For example, int? is an int type that can also have the value null. CTS에서 Nullable 형식은 제네릭 구조체 형식 System.Nullable<T>의 인스턴스입니다.In the CTS, nullable types are instances of the generic struct type System.Nullable<T>. Nullable 형식은 특히 숫자 값이 null일 수 있는 데이터베이스에 데이터를 전달하는 경우에 유용합니다.Nullable types are especially useful when you are passing data to and from databases in which numeric values might be null. 자세한 내용은 Null 허용 형식을 참조하세요.For more information, see Nullable Types.

자세한 내용은 다음 항목을 참조하세요.For more information, see the following topics:

C# 언어 사양C# Language Specification

자세한 내용은 C# 언어 사양을 참조하세요.For more information, see the C# Language Specification. C# 언어 사양은 C# 구문 및 사용법에 대한 신뢰할 수 있는 소스입니다.The language specification is the definitive source for C# syntax and usage.

참고 항목See also