반응형

 

클래스는 참조, 구조체 + 열거는 값
선언 시 0으로 초기화되며 구조체를 new 선언을 하더라도 스택에 저장된다. 이는 만약 모든 타입이 전부 참조 타입으로 되었을 시 가비지 컬렉션 단계에서 많은 지출이 발생할 것이다.

참조 타입은 항상 박싱된 형태이다.

값 타입 주의점_
전체크기가 16바이트 이내여야한다.
16
바이트보다 커도 매개변수, 반환타입으로 쓰는 일이 없다.
GetHashCode
메서드도 수정해야 한다. (필드 값이 일치해야 true반환하게 설정)
추상, 가상함수를 만들 수 없다.
박싱되지 않게되면 메서드의 종료와 동시에 소멸된다.(가비지 컬렉터 X)
가비지 컬렉터의 포인터 지정도 받지 않는다.
다중 스레드 환경에서 인스턴스에 대한 접근 제어를 위해 lock 구문의 설정대상을 할 수 없다.

값 타입이 참조 타입으로 되는 과정(박싱)
1.
관리되는 힙에 메모리가 할당(타입 객체 포인터 + 동기화 블록 인덱스 포함)
2
값 타입 필드가 할당된 힙 메모리에 복사
3.
객체의 메모리 주소 반환 -> 이제 참조 타입으로 취급

참조 타입이 값타입으로 되는 과정(언박싱)
1.
박싱된 객체 내에 들어있는 필드들의 주소를 가져온다.
2.
스택 기반 값 타입 인스턴스 쪽으로 모두 복사한다.

언박싱 작업은 훨씬 적은 연산을 수행

Dynamic Var

 

dynamic 형식 사용 - C# 프로그래밍 가이드

dynamic 형식 사용(C# 프로그래밍 가이드)Using type dynamic (C# Programming Guide) 이 문서의 내용 --> C# 4에서는 새로운 dynamic 형식이 도입되었습니다.C# 4 introduces a new type, dynamic. 이 형식은 정적 형식이지만 dynamic 형식의 개체가 정적 형식 검사를 건너뜁니다.The type is a static type, but an object of type dynamic b

docs.microsoft.com

 

더보기

C# 4에서는 새로운 dynamic 형식이 도입되었습니다. 이 형식은 정적 형식이지만 dynamic 형식의 개체가 정적 형식 검사를 건너뜁니다. 대부분의 경우 이 형식은 object 형식을 가지고 있는 것처럼 작동합니다. 컴파일 시간에 dynamic 형식의 요소는 모든 연산을 지원하는 것으로 간주됩니다. 따라서 개체가 값을 COM API, IronPython 같은 동적 언어, HTML DOM(문서 개체 모델), 리플렉션 또는 프로그램의 다른 곳 등 어디서 가져오든 신경을 쓸 필요가 없습니다. 그러나 코드가 유효하지 않으면 런타임 시 오류가 catch됩니다.

예를 들어 다음 코드의 인스턴스 메서드 exampleMethod1에 매개 변수가 하나뿐인 경우, 컴파일러는 메서드 ec.exampleMethod1(10, 4)에 대한 첫 번째 호출이 유효하지 않음을 인식합니다. 여기에 인수가 두 개 포함되었기 때문입니다. 호출 시 컴파일러 오류가 발생합니다. 컴파일러는 메서드 dynamic_ec.exampleMethod1(10, 4)에 대한 두 번째 호출을 확인하지 않습니다. dynamic_ec의 형식이 dynamic이기 때문입니다. 따라서 컴파일러 오류가 보고되지 않습니다. 그러나 이 오류는 알림을 무기한 이스케이프하지 않고, 런타임에 catch되며 런타임 예외를 일으킵니다.

C#복사

 

static void Main(string[] args) { ExampleClass ec = new ExampleClass(); // The following call to exampleMethod1 causes a compiler error // if exampleMethod1 has only one parameter. Uncomment the line // to see the error. //ec.exampleMethod1(10, 4); dynamic dynamic_ec = new ExampleClass(); // The following line is not identified as an error by the // compiler, but it causes a run-time exception. dynamic_ec.exampleMethod1(10, 4); // The following calls also do not cause compiler errors, whether // appropriate methods exist or not. dynamic_ec.someMethod("some argument", 7, null); dynamic_ec.nonexistentMethod(); }

C#복사

 

class ExampleClass { public ExampleClass() { } public ExampleClass(int v) { } public void exampleMethod1(int i) { } public void exampleMethod2(string str) { } }

이 예제에서 컴파일러의 역할은 dynamic으로 형식이 지정된 개체 또는 식에 대해 각 문이 해야 할 일에 대한 정보를 패키지하는 것입니다. 런타임에는 저장된 정보의 검사가 수행되며, 유효하지 않은 문에서 런타임 예외가 발생합니다.

대부분의 동적 작업은 결과 그 자체가 dynamic입니다. 다음 예제에서 testSum이 사용된 곳에 마우스 포인터를 올려두면 IntelliSense에서 (지역 변수) dynamic testSum 형식을 표시합니다.

C#복사

 

dynamic d = 1; var testSum = d + 3; // Rest the mouse pointer over testSum in the following statement. System.Console.WriteLine(testSum);

결과가 dynamic이 아닌 작업은 다음을 포함합니다.

  • dynamic에서 다른 형식으로의 전환.
  • dynamic 형식의 인수를 포함하는 생성자 호출.

예를 들어 다음 선언에서 testInstance의 형식은 dynamic이 아니라 ExampleClass입니다.

C#복사

 

var testInstance = new ExampleClass(d);

변환 예제는 다음 섹션인 "변환"에 나와 있습니다.

변환

동적 개체와 다른 형식 간에 손쉽게 변환할 수 있습니다. 따라서 개발자는 동적 동작과 비동적 동작 간에 전환할 수 있습니다.

다음 예제와 같이 개체를 동적 형식으로 암시적으로 변환할 수 있습니다.

C#복사

 

dynamic d1 = 7; dynamic d2 = "a string"; dynamic d3 = System.DateTime.Today; dynamic d4 = System.Diagnostics.Process.GetProcesses();

반대로, 암시적 변환을 dynamic 형식의 식에 동적으로 적용할 수 있습니다.

C#복사

 

int i = d1; string str = d2; DateTime dt = d3; System.Diagnostics.Process[] procs = d4;

동적 형식의 인수로 오버로드 확인

메서드 호출 내 하나 이상의 인수에 dynamic 형식이 있거나 메서드 호출의 수신자가 dynamic 형식인 경우 오버로드 확인은 컴파일 시간이 아니라 런타임에 발생합니다. 다음 예제에서 액세스 가능한 유일한 exampleMethod2 메서드가 문자열 인수를 사용하도록 정의되는 경우, d1을 인수로서 전송하면 컴파일러 오류는 발생하지 않지만 런타임 예외가 발생합니다. d1의 런타임 형식은 int인데 exampleMethod2에는 문자열이 필요하므로 오버로드 확인이 런타임에 실패합니다.

C#복사

 

// Valid. ec.exampleMethod2("a string"); // The following statement does not cause a compiler error, even though ec is not // dynamic. A run-time exception is raised because the run-time type of d1 is int. ec.exampleMethod2(d1); // The following statement does cause a compiler error. //ec.exampleMethod2(7);

동적 언어 런타임

DLR(동적 언어 런타임)은 .NET Framework 4의 새로운 API입니다. DLR은 C#에서 dynamic 형식을 지원하는 인프라를 제공하며, IronPython 및 IronRuby와 같은 동적 프로그래밍 언어를 구현합니다. DLR에 대한 자세한 내용은 동적 언어 런타임 개요를 참조하세요.

COM interop

C# 4에는 Office Automation API 등의 COM API와 상호 운용 환경을 개선하는 몇 가지 기능이 포함되어 있습니다. 개선 사항 중에는 dynamic 형식의 사용 및 명명된 인수 및 선택적 인수의 사용이 포함됩니다.

많은 COM 메서드는 형식을 object로 지정하여 인수 형식 및 반환 형식의 변환을 허용합니다. C#에서는 강력한 형식의 변수로 조정하기 위해 값을 명시적으로 캐스팅해야 했습니다. -link(C# 컴파일러 옵션) 옵션을 사용하여 컴파일하는 경우 dynamic 형식을 사용하면 COM 서명에서 object의 발생을 마치 dynamic 형식인 것처럼 취급하여 캐스팅을 상당 부분 피할 수 있습니다. 예를 들어 다음 문은 dynamic 형식은 있고 dynamic 형식은 없는 Microsoft Office Excel 스프레드시트의 셀에 액세스하는 방법과 대조됩니다.

C#복사

 

// Before the introduction of dynamic. ((Excel.Range)excelApp.Cells[1, 1]).Value2 = "Name"; Excel.Range range2008 = (Excel.Range)excelApp.Cells[1, 1];

C#복사

 

// After the introduction of dynamic, the access to the Value property and // the conversion to Excel.Range are handled by the run-time COM binder. excelApp.Cells[1, 1].Value = "Name"; Excel.Range range2010 = excelApp.Cells[1, 1];

 

var - C# 참조

var(C# 참조)var (C# Reference) 이 문서의 내용 --> Visual C# 3.0부터 메서드 범위에서 선언된 변수에 암시적 "형식" var을 사용할 수 있습니다.Beginning in Visual C# 3.0, variables that are declared at method scope can have an implicit "type" var. 암시적 형식 지역 변수는 형식을 직접 선언한 것처럼 강력한 형식이지만 컴파일러가 형식을 결정

docs.microsoft.com

더보기

Visual C# 3.0부터 메서드 범위에서 선언된 변수에 암시적 "형식" var을 사용할 수 있습니다. 암시적 형식 지역 변수는 형식을 직접 선언한 것처럼 강력한 형식이지만 컴파일러가 형식을 결정합니다. i의 다음 두 선언은 기능이 동일합니다.

C#복사

 

var i = 10; // Implicitly typed. int i = 10; // Explicitly typed.

자세한 내용은 암시적 형식 지역 변수  LINQ 쿼리 작업의 형식 관계를 참조하세요.

예제

다음 예제에서는 두 가지 쿼리 식을 보여 줍니다. 첫 번째 식에서는 var을 사용할 수 있지만, 쿼리 결과의 형식을 IEnumerable<string>으로 명시적으로 정의할 수 있기 때문에 필요하지 않습니다. 그러나 두 번째 식에서 var은 결과가 익명 형식의 컬렉션이 되도록 허용하고 해당 형식의 이름은 컴파일러 자체에만 액세스할 수 있습니다. var을 사용하면 결과에 대한 새 클래스를 만들 필요가 없습니다. 예제 #2에서는 foreach 반복 변수 item도 암시적 형식이어야 합니다.

C#복사

 

// Example #1: var is optional when // the select clause specifies a string string[] words = { "apple", "strawberry", "grape", "peach", "banana" }; var wordQuery = from word in words where word[0] == 'g' select word; // Because each element in the sequence is a string, // not an anonymous type, var is optional here also. foreach (string s in wordQuery) { Console.WriteLine(s); } // Example #2: var is required because // the select clause specifies an anonymous type var custQuery = from cust in customers where cust.City == "Phoenix" select new { cust.Name, cust.Phone }; // var must be used because each item // in the sequence is an anonymous type foreach (var item in custQuery) { Console.WriteLine("Name={0}, Phone={1}", item.Name, item.Phone); }

Var는 컴파일 직후에 형이 결정되며, 이후에 박싱된 객체를 불가능한 형태로 언박싱하는 경우가 있으면 예외를 발생시킨다.
Dynamic
은 코드의 흐름대로 형이 바뀌는 것이 진행되며, 최종적으로 사용자가 원하는 형태로 바뀌게 된다. , 실행 시점에서 작성한 코드가 잘못된 동작을 수행하게 될 경우 이에 대한 예외를 일으키게 된다.
또한 변수 자체가 임의의 객체를 가리키고 있기 때문에 객체의 인스턴스 멤버에 대해서만 호출이 가능

 

 

 

ReadOnly

 

 

readonly 키워드 - C# 참조

readonly(C# 참조)readonly (C# Reference) 이 문서의 내용 --> readonly 키워드는 다음 네 가지 컨텍스트에서 사용할 수 있는 한정자입니다.The readonly keyword is a modifier that can be used in four contexts: 필드 선언에서 필드에 대한 할당을 나타내는 readonly는 선언의 일부로 또는 동일한 클래스의 생성자에서만 발생할 수 있습니다.In a field declar

docs.microsoft.com

더보기

readonly 키워드는 다음 네 가지 컨텍스트에서 사용할 수 있는 한정자입니다.

  • 필드 선언에서 필드에 대한 할당을 나타내는 readonly는 선언의 일부로 또는 동일한 클래스의 생성자에서만 발생할 수 있습니다. 필드 선언과 생성자 내에서 읽기 전용 필드를 여러 번 할당 및 재할당할 수 있습니다.

    생성자가 종료된 후에는 readonly 필드를 할당할 수 없습니다. 이 규칙의 의미는 값 형식과 참조 형식에서 서로 다릅니다.

    • 값 형식에는 해당 데이터가 직접 포함되므로, readonly 값 형식인 필드는 변경할 수 없습니다.
    • 참조 형식에는 해당 데이터에 대한 참조가 포함되므로, readonly 참조 형식인 필드는 항상 같은 개체를 참조해야 합니다. 해당 개체는 변경할 수 있습니다. readonly 한정자는 필드가 참조 형식의 다른 인스턴스로 바뀌지 않도록 합니다. 그러나 이 한정자는 필드의 인스턴스 데이터가 읽기 전용 필드를 통해 수정되는 것을 방지하지는 않습니다.

     경고

    변경 가능한 참조 형식인, 외부에서 볼 수 있는 읽기 전용 필드가 포함된 외부에서 볼 수 있는 형식은 보안상 취약할 수 있으며 경고 CA2104 : “변경 가능한 읽기 전용 참조 형식을 선언하지 마세요.”를 실행할 수 있습니다.

  • readonly struct 정의에서 readonly는 struct가 불변임을 나타냅니다.

  • readonly 멤버 정의에서 readonly는 struct의 멤버가 구조체의 내부 상태를 변경하지 않음을 나타냅니다.

  • ref readonly 메서드 반환에서 readonly 한정자는 메서드가 참조를 반환하고 해당 참조에 쓰기가 허용되지 않음을 나타냅니다.

readonly struct  ref readonly 컨텍스트는 C# 7.2에서 추가되었습니다. readonly 구조체 멤버는 C# 8.0에서 추가되었습니다.

읽기 전용 필드 예제

이 예제에서 year 필드의 값은 클래스 생성자에서 할당되었지만 ChangeYear 메서드에서 변경할 수 없습니다.

C#복사

 

class Age { readonly int year; Age(int year) { this.year = year; } void ChangeYear() { //year = 1967; // Compile error if uncommented. } }

다음 컨텍스트에서만 readonly 필드에 값을 할당할 수 있습니다.

  • 변수가 선언에서 초기화될 때. 예를 들면 다음과 같습니다.

    C#복사

     

    public readonly int y = 5;
  • 인스턴스 필드 선언을 포함하는 클래스의 인스턴스 생성자.

  • 정적 필드 선언을 포함하는 클래스의 정적 생성자.

또한 이러한 생성자 컨텍스트에서는 readonly 필드를 out 또는 ref 매개 변수로 전달하는 것이 유효합니다.

 참고

readonly 키워드와 const 키워드와 다릅니다. const 필드는 필드 선언에서만 초기화될 수 있습니다. 필드 선언과 임의 생성자에서 readonly 필드를 여러 번 할당할 수 있습니다. 따라서 readonly 필드는 사용된 생성자에 따라 다른 값을 가질 수 있습니다. 또한 const 필드는 컴파일 시간 상수인 반면, readonly 필드는 다음 예제와 같이 런타임 상수에 사용될 수 있습니다.

C#복사

 

public static readonly uint timeStamp = (uint)DateTime.Now.Ticks;

C#복사

 

class SampleClass { public int x; // Initialize a readonly field public readonly int y = 25; public readonly int z; public SampleClass() { // Initialize a readonly instance field z = 24; } public SampleClass(int p1, int p2, int p3) { x = p1; y = p2; z = p3; } public static void Main() { SampleClass p1 = new SampleClass(11, 21, 32); // OK Console.WriteLine($"p1: x={p1.x}, y={p1.y}, z={p1.z}"); SampleClass p2 = new SampleClass(); p2.x = 55; // OK Console.WriteLine($"p2: x={p2.x}, y={p2.y}, z={p2.z}"); } /* Output: p1: x=11, y=21, z=32 p2: x=55, y=25, z=24 */ }

위 예제에서 다음 예제와 같은 명령문을 사용하는 경우

C#복사

 

p2.y = 66; // Error

컴파일러 오류 메시지가 표시됩니다.

A readonly field cannot be assigned to (except in a constructor or a variable initializer)

읽기 전용 구조체 예제

struct 정의의 readonly 한정자는 구조체가 불변임을 선언합니다. 다음 예제와 같이 struct의 모든 인스턴스 필드를 readonly로 표시해야 합니다.

C#복사

 

public readonly struct Point { public double X { get; } public double Y { get; } public Point(double x, double y) => (X, Y) = (x, y); public override string ToString() => $"({X}, {Y})"; }

앞의 예제는 읽기 전용 자동 속성을 사용하여 스토리지를 선언합니다. 이는 컴파일러가 해당 속성의 readonly 백킹 필드를 만들도록 지시합니다. readonly 필드를 직접 선언할 수도 있습니다.

C#복사

 

public readonly struct Point { public readonly double X; public readonly double Y; public Point(double x, double y) => (X, Y) = (x, y); public override string ToString() => $"({X}, {Y})"; }

readonly로 표시되지 않은 필드를 추가하면 컴파일러 오류 CS8340: "읽기 전용 구조체의 인스턴스 필드는 읽기 전용이어야 합니다."가 발생합니다.

Readonly 멤버 예제

변경을 지원하는 구조체를 만들 수 있는 경우도 있습니다. 이러한 경우 몇 개의 인스턴스 멤버는 구조체의 내부 상태를 수정하지 않을 가능성이 큽니다. readonly 한정자를 사용하여 해당 인스턴스 멤버를 선언할 수 있습니다. 컴파일러에서 의도를 적용합니다. 해당 멤버가 상태를 직접 수정하거나 readonly 한정자로 선언되지 않은 멤버에 액세스하는 경우 컴파일 시간 오류가 발생합니다. readonly 한정자는 struct 멤버에서 유효하지만, class 또는 interface 멤버 선언에서는 유효하지 않습니다.

해당하는 struct 메서드에 readonly 한정자를 적용하면 두 가지 이점이 있습니다. 가장 중요한 이점은 컴파일러에서 의도를 적용하는 것입니다. 상태를 수정하는 코드는 readonly 메서드에서 유효하지 않습니다. 컴파일러는 readonly 한정자를 사용하여 성능을 최적화할 수도 있습니다.  struct 형식을 in 참조로 전달할 때, 구조체의 상태를 수정할 수 있는 경우 컴파일러에서 방어형 복사본을 생성해야 합니다. readonly 멤버에만 액세스하는 경우에는 컴파일러에서 방어형 복사본을 만들 수 없습니다.

readonly 한정자는 System.Object에 선언된 메서드를 재정의하는 메서드를 포함하여 대부분의 struct 멤버에서 유효합니다. 단, 다음과 같은 몇 가지 제한 사항이 있습니다.

  • readonly 정적 메서드 또는 속성을 선언할 수 없습니다.
  • readonly 생성자를 선언할 수 없습니다.

속성 또는 인덱서 선언에 readonly 한정자를 추가할 수 있습니다.

C#복사

 

readonly public int Counter { get { return 0; } set {} // not useful, but legal }

속성 또는 인덱서의 개별 get 또는 set 접근자에 readonly 한정자를 추가할 수도 있습니다.

C#복사

 

public int Counter { readonly get { return _counter; } set { _counter = value; } } int _counter;

속성과 해당 속성의 접근자 중 하나 이상에 readonly 한정자를 모두 추가할 수 없습니다. 동일한 제한이 인덱서에도 적용됩니다.

컴파일러는 컴파일러 구현 코드에서 상태를 수정하지 않는 자동 구현 속성에 readonly 한정자를 암시적으로 적용합니다. 다음 선언과 동일합니다.

C#복사

 

public readonly int Index { get; } // Or: public int Number { readonly get; } public string Message { readonly get; set; }

해당 위치에 readonly 한정자를 추가할 수도 있지만 아무 의미도 없습니다. 자동 구현 속성 setter 또는 읽기/쓰기 자동 구현 속성에 readonly 한정자를 추가할 수 없습니다.

참조 읽기 전용 반환 예

ref return의 readonly 한정자는 반환된 참조를 수정할 수 없음을 나타냅니다. 다음 예제는 원점에 대한 참조를 반환합니다. 예제에서는 readonly 한정자를 사용하여 호출자가 원본을 수정할 수 없음을 나타냅니다.

C#복사

 

private static readonly Point origin = new Point(0, 0); public static ref readonly Point Origin => ref origin;

반환된 유형은 readonly struct일 필요는 없습니다. ref readonly를 통해 ref에서 반환될 수 있는 모든 형식을 반환할 수 있습니다.

해당 변수의 참조를 바꿀 수는 없지만 참조되는 값을 바꿀 수는 있다. , 그 자체로 단일 참조를 이루고 있는 경우는 값을 바꿀 수 없다. (ex) int)

반응형

'C# > CLR via' 카테고리의 다른 글

매개변수 & 프로퍼티  (0) 2020.02.21
메서드  (0) 2020.02.19
Object 그리고 캐스팅  (0) 2020.02.16
CLR과 어셈블리  (0) 2020.02.16
CLR(Common Language RunTime) "공용 런타임"이란  (0) 2020.02.07
Posted by Lotus' Library
,