Section 32.1: Boxing 된 값 타입 변환하기

Boxing 된 값 타입은 원래의 타입으로만 Unboxing 이 가능하며, 이 제약은 두 타입간에 유효한 타입 변환 (valid conversion) 이 존재한다고 해도 마찬가지로 적용된다. 다음 예제를 확인한다:

object boxedInt = (int)1; // int 값이 object 로 Boxing 되었다 long unboxedInt1 = (long)boxedInt; // 유효하지 않은 타입 변환이다

이러한 경우, 먼저 원래의 타입으로 Unboxing 을 수행한 후 타입 변환을 하는 방법을 사용할 수 있다. 다음 예제를 확인한다:

long unboxedInt2 = (long)(int)boxedInt; // 유효한 변환이다
본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

Section 31.5: 메소드에서 ref 와 out 파라미터의 차이 이해하기

값 (value) 타입을 참조 (reference) 형식의 파라미터로 메소드에 전달하는 방법에는 두가지가 있다: refout 이 바로 그것이다. 이 둘의 차이점은, ref 로 전달시에는 해당 값이 반드시 초기화되어 있어야 하지만 out 으로 전달시에는 그럴 필요가 없다는 것이다. 또한 out 파라미터의 경우 해당 변수가 메소드 내에서 호출이 종료되기 전까지 값이 반드시 할당됨을 보장해준다:

public void ByRef(ref int value) { Console.WriteLine(nameof(ByRef) + value); value += 4; Console.WriteLine(nameof(ByRef) + value); } public void ByOut(out int value) { value += 4 // 컴파일 에러 - CS0269: Use of unassigned out parameter `value' Console.WriteLine(nameof(ByOut) + value); // 컴파일 에러 - CS0269: Use of unassigned out parameter `value' value = 4; Console.WriteLine(nameof(ByOut) + value); } public void TestOut() { int outValue1; ByOut(out outValue1); // 4 를 출력한다 int outValue2 = 10; // out 파라미터에 대해서 의미가 없는 값 할당이다 ByOut(out outValue2); // 4 를 출력한다 } public void TestRef() { int refValue1; ByRef(ref refValue1); // 컴파일 에러 - S0165 Use of unassigned local variable 'refValue' int refValue2 = 0; ByRef(ref refValue2); // 0 과 4 가 출력된다 int refValue3 = 10; ByRef(ref refValue3); // 10 과 14 가 출력된다 }

out 파라미터 사용상의 제약이라고 한다면 메소드 호출이 종료되기 전까지 해당 파라미터가 반드시 초기화가 되어야 한다는 것이며, 이를 통해 아래와 같은 메소드 작성시 ref 를 사용하는 것은 아무런 문제가 없지만 out 을 사용하면 컴파일 에러가 발생함을 알 수 있다:

public void EmtyRef(bool condition, ref int value) { if (condition) { value += 10; } } public void EmtyOut(bool condition, out int value) { if (condition) { value = 10; } } // 컴파일 에러 - CS0177: The out parameter 'value' must be assigned before control leaves the current method

이는 condition 파라미터가 참이 아닌 경우, value 파라미터에 값이 할당되지 않기 때문이다.

본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

Section 31.4: Reference 타입에 대한 할당 (assignment) 작업

var a = new List<int>(); var b = a; a.Add(5); Console.WriteLine(a.Count); // 1 이 출력된다 Console.WriteLine(b.Count); // 마찬가지로 1 이 출력된다

하나의 List<int> 를 다른 변수에 할당 (assign) 하는 것은 새로운 List<int> 사본을 생성한다는 것을 의미하지 않는다. 대신에, 해당 List<int> 에 대한 참조 (reference) 를 복사할 뿐이다. 이러한 방식으로 동작하는 타입들을 reference 타입이라 부르게 된다.

본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

Section 31.3: ref 파라미터와 out 파라미터 비교

예제

class Program { static void Main(string[] args) { int a = 20; Console.WriteLine("Inside Main - Before Callee: a = {0}", a); Callee(a); Console.WriteLine("Inside Main - After Callee: a = {0}", a); Console.WriteLine(); Console.WriteLine("Inside Main - Before CalleeRef: a = {0}", a); CalleeRef(ref a); Console.WriteLine("Inside Main - After CalleeRef: a = {0}", a); Console.WriteLine(); Console.WriteLine("Inside Main - Before CalleeOut: a = {0}", a); CalleeOut(out a); Console.WriteLine("Inside Main - After CalleeOut: a = {0}", a); Console.ReadLine(); } static void Callee(int a) { a += 5; Console.WriteLine("Inside Callee a : {0}", a); } static void CalleeRef(ref int a) { a += 10; Console.WriteLine("Inside CalleeRef a : {0}", a); } static void CalleeOut(out int a) { // 여기서 a 는 메소드 선언시에 함께 선언되었을 뿐, 아직 값이 할당되지 않았으므로 a+=15 와 같은 표현을 사용할 수 없다 a = 25; // 이러한 방식으로 초기화를 해주어야 한다 Console.WriteLine("Inside CalleeOut a : {0}", a); } }

출력 결과

Inside Main - Before Callee: a = 20 Inside Callee a : 25 Inside Main - After Callee: a = 20 Inside Main - Before CalleeRef: a = 20 Inside CalleeRef a : 30 Inside Main - After CalleeRef: a = 30 Inside Main - Before CalleeOut: a = 30 Inside CalleeOut a : 25 Inside Main - After CalleeOut: a = 25
본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

Section 31.2: 두개의 다른 변수에 할당된 값이 함께 변경되는 예제

public static void Main(string[] args) { var studentList = new List < Student > (); studentList.Add(new Student("Scott", "Nuke")); studentList.Add(new Student("Vincent", "King")); studentList.Add(new Student("Craig", "Bertt")); // 이후 출력에 사용할 별도의 리스트를 생성한다 var printingList = studentList; // 새로 생성된 리스트 객체이지만, 내부적으로는 동일한 Student 객체들을 가지고 있다 // 각 이름들에서 발견된 오타를 수정한다 studentList[0].LastName = "Duke"; studentList[1].LastName = "Kong"; studentList[2].LastName = "Brett"; // 이제 리스트를 출력한다 PrintPrintingList(printingList); } private static void PrintPrintingList(List < Student > students) { foreach(Student student in students) { Console.WriteLine(string.Format("{0} {1}", student.FirstName, student.LastName)); } }

이 예제에서, printingList 리스트는 학생들의 이름에 존재하는 오타를 수정하기 전에 생성되었지만, PrintPrintingList() 메소드 실행 시 오타가 교정된 이름들이 출력됨을 확인할 수 있다:

Scott Duke Vincent Kong Craig Brett

이는 바로 두 리스트가 모두 동일한 학생 객체들에 대한 참조값을 가지고 있기 때문이다. 따라서 실제 참조의 대상이 되는 Student 객체의 값이 변경되면, 두개의 리스트 모두에 해당 변경사항이 전파된다.

아래 코드는 Student 클래스의 대략적인 모습이다.

public class Student { public string FirstName { get; set; } public string LastName { get; set; } public Student(string firstName, string lastName) { this.FirstName = firstName; this.LastName = lastName; } }
본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

Section 31.1: ref 키워드를 사용해 매개변수를 참조로 전달하기 (pass by reference)

MS 공식 문서 발췌:

C# 에서는, 매개변수를 값 또는 참조 방식으로 전달할 수 있다. 참조 방식으로 전달할 경우, 함수 멤버, 메소드, 속성값 (property), 인덱서, 연산자 (operator) 및 생성자에서 해당 값을 변경할 수 있으며, 이 변경사항은 호출을 수행한 환경에서도 유지되게 된다. 이러한 참조 방식으로 매개변수를 전달하고 싶다면, ref 혹은 out 키워드를 사용할 수 있다.

refout 의 차이점은, out 을 사용할 경우 해당 매개변수는 호출이 종료되기 전까지 새로운 값이 반드시 할당되어야 한다는 점이다. 대조적으로, ref 를 사용해 전달된 매개변수는 값이 변경될 수도, 변경되지 않을 수도 있다.

using System; class Program { static void Main(string[] args) { int a = 20; Console.WriteLine("Inside Main - Before Callee: a = {0}", a); Callee(a); Console.WriteLine("Inside Main - After Callee: a = {0}", a); Console.WriteLine("Inside Main - Before CalleeRef: a = {0}", a); CalleeRef(ref a); Console.WriteLine("Inside Main - After CalleeRef: a = {0}", a); Console.WriteLine("Inside Main - Before CalleeOut: a = {0}", a); CalleeOut(out a); Console.WriteLine("Inside Main - After CalleeOut: a = {0}", a); Console.ReadLine(); } static void Callee(int a) { a = 5; Console.WriteLine("Inside Callee a : {0}", a); } static void CalleeRef(ref int a) { a = 6; Console.WriteLine("Inside CalleeRef a : {0}", a); } static void CalleeOut(out int a) { a = 7; Console.WriteLine("Inside CalleeOut a : {0}", a); } }

출력 결과 :

Inside Main - Before Callee: a = 20 Inside Callee a : 5 Inside Main - After Callee: a = 20 Inside Main - Before CalleeRef: a = 20 Inside CalleeRef a : 6 Inside Main - After CalleeRef: a = 6 Inside Main - Before CalleeOut: a = 6 Inside CalleeOut a : 7 Inside Main - After CalleeOut: a = 7
본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

Section 30.2: IEnumerable<int>

IEnumerable 을 구현 (implement) 하는 객체는 기본적으로 연속된 다른 객체들의 집합을 나타낸다. 이 객체가 나타내는 대상 객체 집합은 C# 의 foreach 키워드를 사용하여 요소 반복을 (iterate) 수행할 수 있다. 아래의 예제에서, sequenceOfNumbers 객체는 IEnumerable 을 구현 (implement) 하고 있으며, 이는 일련의 정수들의 집합을 나타내고 있다. foreach 문을 통해 해당 집합의 요소 반복 (iterate) 이 수행된다.

int AddNumbers(IEnumerable<int> sequenceOfNumbers) { int returnValue = 0; foreach(int i in sequenceOfNumbers) { returnValue += i; } return returnValue; }
본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

Section 30.1: 사용자 구현 Enumerator 와 IEnumerable

IEnumerable 인터페이스를 구현 (implement) 하게 되면, 사용자의 클래스는 BCL 컬렉션들과 마찬가지의 방식으로 열거 (enumerate) 기능을 사용할 수 있게 된다. 이를 위해서는 열거 상태를 추적하는 상속된 Enumerator 클래스를 작성할 필요가 있다.

표준 컬렉션 이외의 대상을 요소 반복 (iterate) 할 필요가 있는 예제로는 다음과 같은 경우가 있을 수 있다:

  • 객체들의 컬렉션이 아닌, 함수로부터 생성되는 일정 범위의 숫자들을 요소 반복하고자 하는 경우
  • 컬렉션을 다른 방식으로 요소 반복하고자 하는 경우, 예를 들어 그래프를 나타내는 컬렉션에 대해 DFS 및 BFS 방식으로 탐색을 수행하는 경우
public static void Main(string[] args) { foreach(var coffee in new CoffeeCollection()) { Console.WriteLine(coffee); } } public class CoffeeCollection: IEnumerable { private CoffeeEnumerator enumerator; public CoffeeCollection() { enumerator = new CoffeeEnumerator(); } public IEnumerator GetEnumerator() { return enumerator; } public class CoffeeEnumerator: IEnumerator { string[] beverages = new string[3] { "espresso", "macchiato", "latte" }; int currentIndex = -1; public object Current { get { return beverages[currentIndex]; } } public bool MoveNext() { currentIndex++; if (currentIndex < beverages.Length) { return true; } return false; } public void Reset() { currentIndex = 0; } } }
본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

+ Recent posts