구조체 (struct)
1. 구조체는 클래스와 동일한 구문을 대부분 공유하지만 클래스보다 제한적입니다.
2. 구조체 선언 내에서 필드는 const 또는 static으로 선언한 경우에만 초기화할 수 있습니다.
3. 구조체는 할당 시 복사됩니다. 구조체가 새 변수에 할당되면 모든 데이터가 복사되고, 새 복사본을 수정해도 원래 복사본의 데이터는 변경되지 않습니다. Dictionary<string, myStruct>와 같은 값 형식의 컬렉션을 사용할 때 이것이 중요합니다.
4. 구조체는 값 형식이고 클래스는 참조 형식입니다.
5. 클래스와 달리 구조체는 new 연산자를 사용하지 않고 인스턴스화할 수 있습니다.
6. 구조체는 매개변수가 있는 생성자를 선언할 수 있습니다.
7. 구조체는 다른 구조체 또는 클래스에서 상속될 수 없으며, 클래스의 기본 클래스가 될 수도 없습니다. 모든 구조체는 System.Object를 상속하는 System.ValueType에서 직접 상속합니다.
8. 구조체는 인터페이스를 구현할 수 있습니다.
9. 구조체를 nullable 형식으로 사용할 수 있고 여기에 null 값을 할당할 수 있습니다.
https://msdn.microsoft.com/ko-kr/library/saxz13w4.aspx
구조체 사용 (struct)
1. 매개 변수가 없는 생성자를 정의하면 오류가 발생합니다.
2. 구조체 본문에서 인스턴스 필드를 초기화해도 오류가 발생합니다.
3. 구조체의 멤버 변수를 초기화 하려면 생성자를 사용하거나 개별적 액세스로 초기화할 수 있습니다.
4. new 연산자를 사용하여 구조체 객체를 생성하면 생성자가 호출됩니다.
5. 클래스와 달리 new 연산자를 사용하지 않고 인스턴스화할 수 있습니다. 이 경우 생성자는 호출되지 않으므로 개별적으로 모든 필드를 초기화 해야합니다.
6. 클래스와 다르게 상속이 없습니다. 그러나 기본 클래스 Object에서 상속할 수 있습니다.
7. 구조체는 클래스에서 인터페이스를 구현하는 것과 동일한 방식으로 인터페이스를 구현할 수 있습니다.
8. 구조체는 값 형식인 반면 클래스는 참조 형식입니다.
9. 참조 형식 구문이 필요한 경우가 아니라면 작은 클래스는 구조체로 대신 선언하면 시스템에서 보다 효율적으로 처리할 수 있습니다.
예제1) 기본 생성자와 매개변수가 있는 생성자로 struct 초기화 하는 방법
public struct CoOrds
{ public int x, y; public CoOrds(int p1, int p2) { x = p1; y = p2; } }
// Declare and initialize struct objects.
class TestCoOrds { static void Main() { // Initialize: CoOrds coords1 = new CoOrds(); CoOrds coords2 = new CoOrds(10, 10); // Display results: Console.Write("CoOrds 1: "); Console.WriteLine("x = {0}, y = {1}", coords1.x, coords1.y); Console.Write("CoOrds 2: "); Console.WriteLine("x = {0}, y = {1}", coords2.x, coords2.y); // Keep the console window open in debug mode. Console.WriteLine("Press any key to exit."); Console.ReadKey(); } } /* Output: CoOrds 1: x = 0, y = 0 CoOrds 2: x = 10, y = 10 */
예제2) new 연산자를 사용하지 않고 객체 생성 방법
public struct CoOrds
{ public int x, y; public CoOrds(int p1, int p2) { x = p1; y = p2; } }
// Declare a struct object without "new." class TestCoOrdsNoNew { static void Main() { // Declare an object: CoOrds coords1; // Initialize: coords1.x = 10; coords1.y = 20; // Display results: Console.Write("CoOrds 1: "); Console.WriteLine("x = {0}, y = {1}", coords1.x, coords1.y); // Keep the console window open in debug mode. Console.WriteLine("Press any key to exit."); Console.ReadKey(); } } // Output: CoOrds 1: x = 10, y = 20
https://msdn.microsoft.com/ko-kr/library/0taef578.aspx
배열
1. 배열 데이터 구조에 동일한 형식의 변수를 여러 개 저장할 수 있습니다.
2. 문법 : type[] arrayName;
Class TestArraysClass { static void Main() { // 1차원 배열 선언 int[] array1 = new int[5]; // 선언과 값 설정 int array2 = new int[] { 1, 3 ,5, 7, 9 }; // 다른 방식 int[] array3 = { 1, 2, 3, 4, 5, 6 }; // 2차원 배열 선언 int[,] multiDimensionalArray1 = new int[2, 3]; // 선언과 값 설정 int[,] multiDimensionalArray2 = { { 1, 2, 3 }, { 4, 5, 6 } }; // 가변 배열 선언 int[][] jaggedArray = new int[6][]; // 가변 배열에서 첫번째 배열에 값 설정 jaggedArray[0] = new int[4] { 1, 2, 3 ,4 }; } }
|
3. 배열은 1차원, 다차원, 가변 배열이 있습니다.
4. 차원 수와 각 차원의 길이는 배열 인스턴스가 생성될 때 만들어집니다. 이러한 값은 인스턴스의 수명 동안 변경할 수 없습니다.
5. 숫자 배열 요소에는 0이, 참조 요소에는 null이 기본값으로 설정됩니다.
6. 배열의 인덱스는 0부터 시작합니다. n개의 요소가 있는 배열의 인덱스는 0부터 n-1까지입니다.
7. 배열 요소는 배열 형식을 포함하여 모든 형식이 될 수 있습니다.
8. 배열 형식은 Array 추상 기본 형식에서 파생된 참조 형식입니다.
9. 이 형식은 IEnumerable 및 IEnumerable<T>을 구현하므로 C#의 모든 배열에 foreach 반복을 사용할 수 있습니다.
https://msdn.microsoft.com/ko-kr/library/9b9dty7d.aspx
1차원 배열
1. 5개의 정수를 포함하는 1차원 배열 선언 int[] array = new int[5]; 이 배열은 array[0]에서 array[4]까지의 요소가 있습니다. 배열을 생성하고 배열 요소를 기본값으로 초기화하려면 new 연산자를 사용합니다. 이 예제에서는 모든 배열 요소를 0으로 초기화합니다. 2. 문자열 배열 선언 string[] stringArray = new string[6]; 3. 배열 초기화 int[] array1 = new int[] { 1, 3, 5, 7, 9 }; 선언 시 배열을 초기화할 수 있으며, 이런 경우 차수는 초기화 목록의 요소 수로 지정되므로 별도로 지정할 필요가 없습니다. 4. 문자열 배열 초기화 선언 string[] weekDays = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; 5. 선언 시 배열을 초기화할 경우 다음과 같이 단축적으로 할 수 있습니다. int[] array2 = { 1, 3, 5, 7, 9 }; string[] weekDays2 = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; 6. 배열 변수를 초기화하지 않고 선언할 수 있지만 이러한 변수에 배열을 할당하려면 new 연산자를 사용해야 합니다. int[] array3; array3 = new int[] { 1, 3, 5, 7, 9 }; // OK // array3 = { 1, 3, 5, 7, 9 } // Error 7. 값 형식 및 참조 형식 배열 SomeType[] array4 = new SomeType[10]; SomeType 배열을 선언하는데 참조 형식인 경우 각 요소는 null 참조로 초기화 됩니다. |
https://msdn.microsoft.com/ko-kr/library/0a7fscd0.aspx
c# 연산자
<기본 연산자>
1. x.y
- 도트 연산자(.), 멤버 엑세스에 사용
Class Simple { public int a; public void b() { } } Simple s = new Simple(); s.a = 6; s.b(); // 변수 s 에는 a 및 b 두 멤버가 있습니다. 이들 멤버에 엑세스 하기 위해 도트 연산자를 사용합니다. System.Console.WriteLine("hello"); // 해당 멤버가 속한 네임스페이스나 인터페이스 등에서도 사용합니다. namespace Example2 { class console { public static void Write(string s) {} } } namespace Example1 { using Example2; class C { void M() { System.Console.WriteLine("hello"); Example2.Console.WriteLine("hello"); } } } // 식별자가 모호할 경우 사용 |
2. x?.y
- null 조건부 멤버 엑세스(?.), 인덱스 작업(?[)null 검사를 위한 코드의 양을 줄이는데 도움이 된다.
int? length = customers?.Length; // customers 가 null 이면 null Customer first = customers?[0]; // customers 가 null 이면 null int? count = customers?[0]?.Orders?.Count(); // customers, [0], Orders 가 null 이면 null |
조건부 멤버 엑세스 및 인덱스 작업 체인의 한 작업이 null을 반환하면 나머지 부분은 중지됩니다.
A?.B?.C?[0] ?? E A?.B?.C?[0] == E // Null 조건부 연산자 |
대리자 호출 예제 예전 방식 var handler = this.PropertyChanged; if (handler != null) handler (...) 새로운 방식 PropertyCanged?.Invoke(e) |
새로운 방식은 컴파일러가 PropertyChanged를 한 번만 평가하는 코드를 생성하고 결과를 임시 변수에 유지하기때문에 스레드로부터 안전합니다.
3. f(x)
- 괄호 연산자, 함수 호출
- 식에서 연산의 순서를 지정하기 위해 사용
- 캐스팅은 구문을 모호하게 할 수 있습니다. 예를 들면 (x)-y는 -y를 x 형식으로 캐스팅하는 의미로 해석될 수 있고, x-y의 가감식으로 해석될 수 있습니다.
1) 캐스팅 또는 형식 변황을 지정합니다. double x = 1234.7; int a; a = (int)x; 2) 메서드 또는 대리자 호출 TestMethod(); |
4. a[x]
- 집계 객체 인덱싱
- 대괄호([])는 배열, 인덱서 및 특성에 사용합니다 또한 포인터에도 사용합니다.
1) 배열 형식 int[] fib; // int 형 배열 fib = new int[100]; // int 형 배열 100개 생성 fib[0] = fib[1] = 1; for (int i = 2; i < 100; ++i) fib[i] = fib[i - 1] + fib[i - 2]; // 배열 인덱스가 범위를 벗어나면 예외가 throw 됩니다. 2) Hashtable 형식 System.Collections.hashtable h = new System.Collections.Hashtable(); h["a"] = 123; // a 를 인덱스로 사용 3) 특성을 지정 [Conditional("DEBUG")] void TraceMethod() {} 4) 포인터의 인덱스 참조에 사용할 수 있습니다. unsafe void M() { int[] nums = { 0, 1, 2, 3 ,4, 5 }; fixed ( int* p = nums ) { p[0] = p[1] = 1; for ( int i=2; i<100; ++i ) p[i] = p[i-1] + p[i-2]; } } |
5. a?[x]
- null 조건부 인덱싱. 왼쪽 피연산자가 null인 경우 null을 반환합니다.
- 2번 x?.y 참조
6. x++
- 후위 증가. x의 값을 반환하고 x에 1을 더합니다.
Class MainClass { static void Main() { double x; x = 1.5; Console.WriteLine(++x); // 2.5 x = 1.5; Console.WriteLine(x++); // 1.5 console.WriteLine(x); // 2.5 } } |
7. x--
- 후위 감소. x의 값을 반환하고 x에 1을 뺍니다.
Class MainClass { static void Main() { double x; x = 1.5; Console.WriteLine(--x); // 0.5 x = 1.5; Console.WriteLine(x--); // 1.5 Console.WriteLine(x); // 0.5 } } |
8. New
- 형식 인스턴스화
1) 객체를 만들고 생성자를 호출하는 데 사용됩니다. Class1 obj = new Class1() 2) 익명 형식의 인스턴스를 만드는 데도 사용됩니다. var query = from cust in customers select new {Name = cust.Name, Address = cust.Primaryaddress}; 3) 값 형식에 대한 기본 생성자를 호출하는 데도 사용됩니다. int i = new int(); // int 형식의 기본값인 0으로 초기화됩니다. int i = 0; // 두 문의 결과는 같다. |
- 모든 값 형식에는 암시적으로 공용 기본 생성자가 포함되기 때문에 구조체에 대한 기본 생성자를 선언하면 오류가 발생합니다.
- 구조체는 매개변수가 있는 생성자를 선언하여 그 초기값을 설정할 수 있지만 이 방법은 기본값이 아닌 다른 값이 필요한 경우에만 사용해야 합니다.
- 구조체와 같은 값 형식 개체는 스택에 만들어지고 클래스 같은 참조 형식 개체는 힙에 만들어집니다.
- new 연산자는 오버로드 되지 않습니다.
- new 연산자가 메모리 할당에 실패하면 OutOfMemoryexception 예외를 던집니다.
struct SampleStruct { public int x; public int y; public SampleStruct(int x, int y) { this.x = x; this.y = y; } } class SampleClass { public string name; public int id; public SampleClass() {} public SampleClass(int id, string name) { this.id = id; this.name = name; } } class ProgramClass { static void Main() { // 기본 생성자를 사용하여 객체 생성 SampleStruct Location1 = new SampleStruct(); SampleClass Employee1 = new SampleClass(); // Display values: Console.WriteLine("Default values:"); Console.WriteLine(" Struct members: {0}, {1}", Location1.x, Location1.y); Console.WriteLine(" Class members: {0}, {1}", Employee1.name, Employee1.id); // 매개변수를 가진 생성자를 사용하여 객체 생성 SampleStruct Location2 = new SampleStruct(10, 20); SampleClass Employee2 = new SampleClass(1234, "Cristina Potra"); // Display values: Console.WriteLine("Assigned values:"); Console.WriteLine(" Struct members: {0}, {1}", Location2.x, Location2.y); Console.WriteLine(" Class members: {0}, {1}", Employee2.name, Employee2.id); } } /* Output: Default values: Struct members: 0, 0 Class members: , 0 Assigned values: Struct members: 10, 20 Class members: Cristina Potra, 1234 */ |
9. Typeof
- 피연산자(operand)를 나타내는 System.Type 개체를 반환합니다.
- System.Type 객체를 얻는 데 사용됩니다.
- typeof 연산자는 오버로드되지 않습니다.
typyof 형식 System.Type type = typeof(int); GetType() 메서드 사용 int i = 0; System.Type type = i.GetType(); |
- typeof 연산자는 열린 제네릭 형식에도 사용할 수 있습니다.
string s = method.ReturnType.GetInterface(typeof(System.Collections.Generic.IEnumerable<>).FullName); |
메소드 정보 얻기 public class ExampleClass { public int sampleMember; public void SampleMethod() {} static void Main() { Type t = typeof(ExampleClass); // Alternatively, you could use // ExampleClass obj = new ExampleClass(); // Type t = obj.GetType(); Console.WriteLine("Methods:"); System.Reflection.MethodInfo[] methodInfo = t.GetMethods(); foreach (System.Reflection.MethodInfo mInfo in methodInfo) Console.WriteLine(mInfo.ToString()); Console.WriteLine("Members:"); System.Reflection.MemberInfo[] memberInfo = t.GetMembers(); foreach (System.Reflection.MemberInfo mInfo in memberInfo) Console.WriteLine(mInfo.ToString()); } } /* Output: Methods: Void SampleMethod() System.String ToString() Boolean Equals(System.Object) Int32 GetHashCode() System.Type GetType() Members: Void SampleMethod() System.String ToString() Boolean Equals(System.Object) Int32 GetHashCode() System.Type GetType() Void .ctor() Int32 sampleMember */ |
숫자 계산을 위한 type 확인을 위해 GetType 메서드 사용 class GetTypeTest { static void Main() { int radius = 3; Console.WriteLine("Area = {0}", radius * radius * Math.PI); Console.WriteLine("The type is {0}", (radius * radius * Math.PI).GetType() ); } } /* Output: Area = 28.2743338823081 The type is System.Double */ |
10. checked
- 정수 계열 형식의 산술 연산 및 변환에 대한 오버플로 검사를 명시적으로 활성화
- 기본적으로 식이 상수 값만으로 되어 있고 형식의 범위를 초과 한다면 컴파일러 오류가 발생합니다.
- 식이 상수가 아닌 값을 하나 이상 포함하는 경우 컴파일러가 오버플로를 검색하지 않습니다.
// 정수형의 최대치인 2147483647을 넘는다면 컴파일러 에러 CS0220이 발생합니다. int i1 = 2147483647 + 10; // 변수 ten 이 포함된 다음 예제는 컴파일러 에러를 발생시키지 않습니다. int ten = 10; int i2 = 2147483647 + 10; Console.WriteLine(i2); // 결과 : -2,147,483,639 |
- 기본적으로 상수가 아닌 이러한 식에서는 런타임 에러 오버플로가 검사되지 않습니다.
- 컴파일러 옵션, 환경 구성 또는 checked 키워드 사용을 통해 오버플로 검사를 활성화할 수 있습니다.
- 다음 예제에서는 checked 식이나 checked 블록을 사용하여 오버플로를 검색하는 방법을 보여줍니다.
// checked 식 Console.WriteLine(checked(2147483647 + ten)); // checked 블럭 checked { int i3 = 2147483647 + ten; Console.WriteLine(i3); } |
- unchecked 키워드는 오버플로 검사를 막기 위해 사용될 수 있습니다.
- 다음 예제는 checked 키워드로 오버플로 검사 예제입니다.
class OverFlowTest { // int 형 최대값을 maxIntValue 에 설정합니다. static int maxIntValue = 2147483647; // checked 식 static int CheckedMethod() { int z = 0; try { // 다음 라인은 checked 를 사용했기 때문에 예외를 발생시킵니다. z = checked(maxIntValue + 10); } catch (System.OverflowException e) { Console.WriteLine("CHECKED and CAUGHT: " + e.ToString()); } return z; } // unchecked 식. static int UncheckedMethod() { int z = 0; try { // 다음 계산은 unchecked 이기 때문에 예외를 발생시키지 않습니다. z = maxIntValue + 10; } catch (System.OverflowException e) { Console.WriteLine("UNCHECKED and CAUGHT: " + e.ToString()); } // 오버플로가 체크되지 않았기 때문에 2147483647 + 10 은 -2147483639 가 반환됩니다. return z; } static void Main() { Console.WriteLine("\nCHECKED output value is: {0}", CheckedMethod()); Console.WriteLine("UNCHECKED output value is: {0}", UncheckedMethod()); } /* Output: CHECKED and CAUGHT: System.OverflowException: Arithmetic operation resulted in an overflow. at ConsoleApplication1.OverFlowTest.CheckedMethod() CHECKED output value is: 0 UNCHECKED output value is: -2147483639 */ } |
https://msdn.microsoft.com/ko-kr/library/6a71f45d.aspx
11. unchecked
1. 정수 계열 형식의 산술 연산 및 변환에 대한 오버플로 검사를 비활성화하는 데 사용됩니다.
2. unchecked 컨텍스트 내에서는, 식의 결과 값이 대상 형식의 범위를 벗어나는 경우, 오버플로 플래그가 세워지지 않습니다.
3. 예를 들어, 다음 예제의 계산은 unchecked 블록이나 식의 안쪽에서 수행되므로 결과값이 정수로서는 너무 크다는 사실이 무시되고, int1에 값 -2,147,483,639이 할당됩니다.
unchecked { int1 = 2147483647 + 10; } int1 = unchecked(ConstantMax + 10);
3. unchecked 환경을 제거하면 컴파일 오류가 발생합니다.
4. 식의 모든 항이 상수이기 때문에 컴파일 시점에 오버플로를 감지할 수 있습니다.
5. 비상수 항을 포함하는 식은 기본적으로 컴파일 시점과 실행 시점이 검사되지 않습니다.
6. 오버플로를 검사하는 작업은 시간이 걸리기 때문에 오버플로 위험이 없는 경우 unchecked 코드를 사용하면 성능을 향상시킬 수 있습니다.
7. 그러나 오버플로가 발생할 수 있는 경우 checked 환경을 사용해야 합니다.
class UncheckedDemo
{ static void Main(string[] args) { // int.MaxValue is 2,147,483,647. const int ConstantMax = int.MaxValue; int int1; int int2; int variableMax = 2147483647; // 다음 문은 기본적으로 컴파일 타임에 체크되고, 컴파일 되지 않습니다. //int1 = 2147483647 + 10; //int1 = ConstantMax + 10; // int1에 할당을 하고 컴파일과 실행을 하려면 unchecked 블록이나 식 안에 두어야 합니다. // 다음 식은 컴파일되고 실행 됩니다. unchecked { int1 = 2147483647 + 10; } int1 = unchecked(ConstantMax + 10); // 2,147,483,647 과 10 의 합은 -2,147,483,639 로 표시됩니다. Console.WriteLine(int1); // 다은 문은 기본적으로 컴파일 타임과 실행 타임에 체크되지 않습니다. // 식이 변수 variableMax를 포함하기 때문입니다. // 오버플로를 발생시키지만 오버플로로 발견되지는 않습니다. 문은 컴파일되고 실행됩니다. int2 = variableMax + 10; // 다시, 2,147,483,647 과 10 의 합계가 -2,147,483,639 로 표시됩니다. Console.WriteLine(int2); // 실행 타임때 int2에 할당에 대한 오버플로를 잡으려면 checked 블록이나 식 안에 두어야 합니다. // 다음 문은 컴파일 되지만 실행 타임에 오버플로 예외를 일으킵니다. checked { //int2 = variableMax + 10; } //int2 = checked(variableMax + 10); // Unchecked 섹션은 checked 환경에서 자주 사용되는데 // 오버플로 예외를 예상하지 못한 코드의 부분에서의 성능 향상을 위해서 입니다. checked { // 오버플로를 발생시킬 수도 있는 코드가 checked 환경에서 실행된다. unchecked { // 이 섹션은 성능이 우선되고 오버플로가 발생하지 않을 것을 확신할 때 적절합니다. } // 추가 체크 코드 } } }
12. Delegate (대리자)
1. 코드 블럭을 대리자 매개변수로 넘기는 두가지 방법
// 클릭 이벤트 핸들러 만듦 button1.Click += delegate(System.Object o, System.EventArgs e) { System.Windows.Forms.MessageBox.Show("Click!"); };
// 대리자 생성 delegate void Del(int x); // 무명 메서드를 사용해서 대리자 인스턴스 만듦 Del d = delegate(int k) { /* ... */ };
2. 무명 메서드를 사용하면 별도의 메서드를 만들 필요가 없으므로 대리자의 인스턴스를 만드는데에 따른 코드 오베헤드가 없다.
3. 다음 코드는 스레드에 실행 코드가 포함되어 있으므로 별도의 대리자의 메서드를 만들 필요가 없다.
void StartThread() { System.Threading.Thread t1 = new System.Threading.Thread (delegate() { System.Console.Write("Hello, "); System.Console.WriteLine("World!"); }); t1.Start(); }
4. 무명 메서드 블록 안에서 블록 밖으로나 안을 대상으로 goto, break, 또는 continue와 같은 점프 문을 사용하면 오류가 발생한다.
5. 지역 변수 및 매개 변수의 범위에 무명 메서드 선언이 포함되는 경우 이러한 변수를 무명 메서드의 외부 변수라고 합니다.
6. 다음 코드에서 n은 외부 변수 입니다.
7. 무명 메서드를 참조하는 대리자가 가비지 수집이 될 때까지 외부 변수 n의 수명은 확장합니다.
8. 무명 메서드에서는 외부 범위의 ref 또는 out 매개 변수에 액세스할 수 없습니다.
9. 무명 메서드는 is 연산자의 왼쪽에 사용할 수 없습니다.
int n = 0;
Del d = delegate() { System.Console.WriteLine("Copy #:{0}", ++n); };
10. 다음 예제에서는 대리자를 인스턴스화하는 두 가지 방법을 보여 줍니다.
- 대리자를 무명 메서드에 연결
- 대리자를 명명된 메서드(named method)에 연결
delegate void Printer(string s); class TestClass { static void Main() { // 무명 메서드를 사용해서 대리자 형식을 인스턴스화 Printer p = delegate(string j) { System.Console.WriteLine(j); }; // 무명 대리자 호출로부터의 결과 p("The delegate using the anonymous method is called."); // 명명된 메서드 "DoWork" 를 사용해서 대리자 인스턴스화 p = new Printer(TestClass.DoWork); // 구식 스타일 대리자 호출로부터의 결과 p("The delegate using the named method is called."); } // 명명된 대리자와 연결된 메서드 static void DoWork(string k) { System.Console.WriteLine(k); } } /* Output: The delegate using the anonymous method is called. The delegate using the named method is called. */
13. sizeof
1. 관리되지 않는 형식에 대한 바이트 단위의 크기를 가져오는데 사용됩니다.
- 열거형 형식
- 포인터 형식
- 참조 형식인 필드나 속성을 포함하지 않는 사용자 정의 구조체
2. 다음 예제에서는 int의 크기를 검색하는 방법을 보여줍니다.
// 상수 값 4: int intSize = sizeof(int);
3. C# 2.0부터는 기본 제공 형식(built-in types)에 sizeof를 적용할 때 unsafe 모드를 사용하지 않아도 됩니다.
4. sizeof 연산자는 오버로드되지 않습니다.
5. sizeof 연산자가 반환하는 값은 int 형식입니다.
6. 다음 표는 특정 기본 제공 형식을 피연산자로 사용하는 sizeof식 대신 사용되는 상수 값을 보여줍니다.
식 | 상수 값 |
---|---|
sizeof(sbyte) | 1 |
sizeof(byte) | 1 |
sizeof(short) | 2 |
sizeof(ushort) | 2 |
sizeof(int) | 4 |
sizeof(uint) | 4 |
sizeof(long) | 8 |
sizeof(ulong) | 8 |
sizeof(char) | 2(유니코드) |
sizeof(float) | 4 |
sizeof(double) | 8 |
sizeof(decimal) | 16 |
sizeof(bool) | 1 |
7. 구조체를 포함한 다른 모든 형식의 경우에는 안전하지 않은 코드 블록에서만 sizeof 연산자를 사용할 수 있습니다.
8. Marshal.SizeOf 메서드를 사용할 수 있지만 이 메서드가 반환하는 값이 sizeof가 반환하는 값과 항상 같지는 않습니다.
9. Marshal.SizeOf는 형식이 마샬링된 후의 크기를 반환한다.
10. 하지만 sizeof는 패딩을 포함하여 공용 언어 런타임에서 할당된 크기를 반환합니다.
class MainClass { // unsafe는 원시형에는 필요치 않다.(unsafe not required for primitive types) static void Main() { Console.WriteLine("The size of short is {0}.", sizeof(short)); Console.WriteLine("The size of int is {0}.", sizeof(int)); Console.WriteLine("The size of long is {0}.", sizeof(long)); } } /* Output: The size of short is 2. The size of int is 4. The size of long is 8. */
string
1. 문자열은 값이 텍스트인 string 형식의 개체입니다.
2. 내부적으로 텍스트는 Char 객체의 순차적(sequential) 읽기 전용 컬렉션으로 저장됩니다.
3. C# 문자열의 끝에는 null 종결 문자가 없습니다.
4. C# 문자열은 null 문자(\n)을 제한 없이 포함할 수 있습니다.
5. 문자열의 Length 속성은 유니코드 문자의 수가 아니라 포함된 Char 개체의 수를 나타냅니다.
6. 문자열에서 개별 유니코드 포인트에 액세스하려면 StringInfor 개체를 사용합니다.
// 초기화 없이 선언. string message1; // null로 초기화 string message2 = null; // 빈 문자열로 초기화 // 리터럴 "" 대신 Empty 상수 사용 string message3 = System.String.Empty; //정규 문자열 리터럴로 초기화 string oldPath = "c:\\Program Files\\Microsoft Visual Studio 8.0"; // verbatim string literal로 초기화 string newPath = @"c:\Program Files\Microsoft Visual Studio 9.0"; // 선호한다면 System.String 을 사용 System.String greeting = "Hello World!"; // 지역 변수에서 (예를 들면 메소드 몸체 내에서) // 암묵적 타입을 사용할 수 있다. var temp = "I'm still a strongly-typed System.String!"; // const 문자열을 사용하여 message4가 다른 문자열 값을 저장하는 것을 막아라. const string message4 = "You can't get rid of me!"; // char*, char[], sbyte* 로부터 문자열을 만들 때 문자열 생성자를 사용하라.
// 자세한 사항은 System.String 문서를 참조. char[] letters = { 'A', 'B', 'C' }; string alphabet = new string(letters);
7. 문자열을 문자(Char) 배열로 초기화할 경우 이외에는 new 연산자를 사용하여 문자열 개체를 만들지 마십시오.
8. Empty 상수 값으로 문자열을 초기화하여 문자열 길이가 0인 String 개체를 새로 만듭니다.
9. 길이가 0인 문자열의 문자열 리터럴 표현은 ""입니다.
10. 문자열을 null 대신 Empty 값으로 초기화하면 NullReferenceException 발생 위험을 줄일 수 있습니다.
11. 문자열에 액세스하기 전에 문자열 값을 확인하려면 static IsNullOrEmpty(string) 메서드를 사용합니다.
문자열 객체의 불변성
1. 문자열 객체는 한 번 만들어지면 변경할 수 없는 변경 불가능 객체입니다.
2. 문자열을 수정하는 것처럼 보이는 모든 string 메서드 및 C# 연산자는 실제로드는 새 문자열 객체의 결과를 반환합니다.
3. 다음 예제에서 s1과 s2의 내용이 결합되어 단일 문자열이 만들어질 때, 두 원본 문자열은 변경되지 않습니다.
4. 새 객체는 s1 변수에 할당되고 s1에 할당되었던 원래 객체는 해당 객체에 대한 참조를 유지하는 다른 변수가 없으므로 가비지 수집을 위해 해제됩니다.
string s1 = "A string is more "; string s2 = "than the sum of its chars."; // s1과 s2를 연결합니다. 이것은 실제로는 // 새 문자열 객체를 만들어서 s1에 저장하고 // 원래 객체의 참조를 해제합니다. s1 += s2; System.Console.WriteLine(s1); // 출력: A string is more than the sum of its chars.
5. 문자열 수정이 실제로는 새 문자열 생성이므로 문자열에 대한 참조를 만들 때 주의해야 합니다.
6. 문자열에 대한 참조를 만든 다음 원래 문자열을 수정할 경우 해당 참조는 문자열을 수정할 때 만든 새 객체 대신 원래 객체를 계속해서 가리킵니다.
string s1 = "Hello "; string s2 = s1; s1 += "World"; System.Console.WriteLine(s2); //Output: Hello
일반 문자열 및 약어 문자열 리터럴
string columns = "Column 1\tColumn 2\tColumn 3"; //Output: Column 1 Column 2 Column 3 string rows = "Row 1\r\nRow 2\r\nRow 3"; /* Output: Row 1 Row 2 Row 3 */ string title = "\"The \u00C6olean Harp\", by Samuel Taylor Coleridge"; //Output: "The Æolean Harp", by Samuel Taylor Coleridge
1. 문자열 텍스트에 파일 경로 등의 백슬래시 문자가 포함되는 경우에는 사용 편의성과 가독성을 향상시킬 수 있도록 약어 문자열(verbatim string)을 사용합니다.
2. 약어 문자열은 줄 바꿈 문자를 문자열 텍스트의 일부로 포함하므로 여러 줄 문자열을 초기화하는 데 사용할 수 있습니다.
3. 약어 문자열 내에 인용 부호를 포함하려면 큰 따옴표를 사용합니다.
string filePath = @"C:\Users\scoleridge\Documents\"; //Output: C:\Users\scoleridge\Documents\ string text = @"My pensive SARA ! thy soft cheek reclined Thus on mine arm, most soothing sweet it is To sit beside our Cot,..."; /* Output: My pensive SARA ! thy soft cheek reclined Thus on mine arm, most soothing sweet it is To sit beside our Cot,... */ string quote = @"Her name was ""Sara."""; //Output: Her name was "Sara."
문자열 이스케이프 시퀀스
이스케이프 시퀀스 | 문자 이름 | 유니코드 인코딩 |
---|---|---|
\' | 작은따옴표 | 0x0027 |
\" | 큰따옴표 | 0x0022 |
\\ | 백슬래시 | 0x005C |
\0 | Null | 0x0000 |
\a | 경고 | 0x0007 |
\b | 백스페이스 | 0x0008 |
\f | 폼 피드 | 0x000C |
\n | 줄 바꿈 | 0x000A |
\r | 캐리지 리턴 | 0x000D |
\t | 가로 탭 | 0x0009 |
\U | 서로게이트 쌍에 대한 유니코드 이스케이프 시퀀스 | \Unnnnnnnn |
\u | 유니코드 이스케이프 시퀀스 | \u0041 = "A" |
\v | 세로 탭 | 0x000B |
\x | 가변 길이를 특징으로 하는 "\u"와 유사한 유니코드 이스케이프 시퀀스 | \x0041 = "A" |
참고
1. 컴파일 타임에 약어 문자열은 동일한 이스케이프 시퀀스를 갖는 보통 문자열로 변환 됩니다.
2. 디버거 조사식 창에서 보면 다음으로 나타납니다. 예) @"C:\files.txt" -> "C:\\files.txt"
형식 문자열
1. 형식 문자열은 런타임에 동적으로 내용을 결정할 수 있는 문자열입니다.
2. static Format 메서드를 사용하고 런타입에 다른 값으로 대체될 내용에 해당하는 자리 표시자를 중괄호로 묶는 방법으로 형식 문자열을 만들 수 있습니다.
class FormatString { static void Main() { // 유저 입력 받음. System.Console.WriteLine("Enter a number"); string input = System.Console.ReadLine(); // 입력 내용을 int 형으로 변환 int j; System.Int32.TryParse(input, out j); // 각 반복에 다른 문자열을 출력 string s; for (int i = 0; i < 10; i++) { // 정렬 포맷 없는 간단한 형식 문자열 s = System.String.Format("{0} times {1} = {2}", i, j, (i * j)); System.Console.WriteLine(s); } // 디버그 모드에서 콘솔 창을 열린 채로 유지 System.Console.ReadKey(); } }
부분 문자열
1. 부분 문자열(substring)은 문자열에 포함된 임의의 문자 시퀀스입니다.
2. Substring 메서드를 사용하면 원래 문자열의 일부를 새 문자열로 만들 수 있습니다.
2. IndexOf 메서드를 사용하면 하나 이상의 부분 문자열 항목을 검색할 수 있습니다.
3. Replace 메서드를 사용하면 지정된 부분 문자열의 모든 항목을 새 문자열로 바꿀 수 있습니다.
4. Substring 메서드와 마찬가지로 replace는 실제로 새 문자열을 반환하고 원래 문자열을 수정하지 않습니다.
string s3 = "Visual C# Express"; System.Console.WriteLine(s3.Substring(7, 2)); // Output: "C#" System.Console.WriteLine(s3.Replace("C#", "Basic")); // Output: "Visual Basic Express" // Index values are zero-based int index = s3.IndexOf("C"); // index = 7
개별 문자 액세스
1. 인덱스 값을 이용한 배열 표기법을 사용하여 개별 문자열에 읽기 전용으로 액세스할 수 있습니다.
string s5 = "Printing backwards"; for (int i = 0; i < s5.Length; i++) { System.Console.Write(s5[s5.Length - i - 1]); } // Output: "sdrawkcab gnitnirP"
2. StringBuilder 객체를 사용하여 개별 문자를 수정할 수 있습니다.
string question = "hOW DOES mICROSOFT wORD DEAL WITH THE cAPS lOCK KEY?"; System.Text.StringBuilder sb = new System.Text.StringBuilder(question); for (int j = 0; j < sb.Length; j++) { if (System.Char.IsLower(sb[j]) == true) sb[j] = System.Char.ToUpper(sb[j]); else if (System.Char.IsUpper(sb[j]) == true) sb[j] = System.Char.ToLower(sb[j]); } // 새 문자열을 저장 string corrected = sb.ToString(); System.Console.WriteLine(corrected); // Output: How does Microsoft Word deal with the Caps Lock key?
Null 문자열 및 빈 문자열
1. 빈 문자열은 문자가 들어 있지 않은 System.String 개체의 인스턴스입니다.
2. 빈 문자열은 다음과 같이 초기화됩니다.
string s = String.Empty;
3. 이와 반대로 null 문자열은 String.String 객체의 인스턴스를 참조하지 않으며 null 문자열에서 메서드를 호출하려고 하면 NullReferenceException이 발생합니다.
4. 그러나 문자열 연결(concatenation)과 비교 연산에서는 null 문자열을 사용할 수 있습니다.
static void Main() { string str = "hello"; string nullStr = null; string emptyStr = String.Empty; string tempStr = str + nullStr; // 다음 라인의 결과: hello Console.WriteLine(tempStr); bool b = (emptyStr == nullStr); // 다음 라인의 결과: False Console.WriteLine(b); // 다음 라인은 새 빈 문자열을 만듭니다. string newStr = emptyStr + nullStr; // Null 문자열과 빈 문자열은 다르게 작동합니다. // 다음 두 라인은 0을 표시합니다. Console.WriteLine(emptyStr.Length); Console.WriteLine(newStr.Length); // 다음 라인은 NullReferenceException 을 발생시킵니다. //Console.WriteLine(nullStr.Length); // character 문자는 다른 Chars 처럼 표시되고 카운트될 수 있습니다. string s1 = "\x0" + "abc"; string s2 = "abc" + "\x0"; // 다음 라인의 결과: * abc* Console.WriteLine("*" + s1 + "*"); // 다음 라인의 결과: *abc * Console.WriteLine("*" + s2 + "*"); // 다음 라인의 결과: 4 Console.WriteLine(s2.Length); }
빠른 문자열 생성을 위해 StringBuilder 사용
1. .NET의 문자열 작업은 매우최적화되어 있어 대부분의 경우 성능에 영향을 미치지 않습니다.
2. 하지만 수백 번이나 수천 번 이상 실행되는 루프 같은 일부 시나리오에서는 문자열 작업이 성능에 영향을 줄 수 있습니다.
3. StringBuilder 클래스는 프로그램에서 수행할 문자열 조작 작업이 많을 경우 성능을 향상시켜 주는 문자열 버퍼를 만듭니다.
4. 다음 예제는 새 문자열을 만들지 않고 문자열의 내용을 변경합니다.
System.Text.StringBuilder sb = new System.Text.StringBuilder("Rat: the ideal pet"); sb[0] = 'C'; System.Console.WriteLine(sb.ToString()); System.Console.ReadLine(); //결과: Cat: the ideal pet
5. 다음 예제는 StringBuilder 객체를 사용하여 숫자 형식의 집합에서 문자열을 만듭니다.
class TestStringBuilder { static void Main() { System.Text.StringBuilder sb = new System.Text.StringBuilder(); // 0 - 9 로 구성된 문자열을 만듭니다. for (int i = 0; i < 10; i++) { sb.Append(i.ToString()); } System.Console.WriteLine(sb); // 결과 0123456789 // 문자열 한개를 복사합니다. (System.String 으로는 불가능) sb[0] = sb[9]; System.Console.WriteLine(sb); // 결과 9123456789 } }
문자열 내용 수정
1. 문자열은 변경 불가능이므로 문자열 객체를만든 후에 안전하지 않은 코드를 사용하지 않고는 ㅁ ㅜㄴ자열 개체의 값을 수정할 수 없습니다.
2. 하지만 문자열 값을 수정하여 그 결과를 새 문자열 객체에 저장하는 방법은 많습니다.
3. System.String 클래스는 입력 문자열을 처리하여 새 문자열 객체를 반환하는 메서드를 제공합니다.
4. 많은 경우에 새 객체를 원래 문자열을 가지는 변수에 할당할 수 있습니다.
5. System.Text.RegularExpressions.Regex 클래스는 유사한 방식으로 작동하는 추가 메서드를 제공합니다.
6. System.Text.StringBuilder 클래스는 내부에서 수정할 수 있는 문자 버퍼를 제공합니다.
7. StringBuilder.ToString 메서드를 호출하여 버퍼의 현재 내용을 포함하는 새 문자열 객체를 만들 수 있습니다.
8. 다음 예제는 지정된 문자열에서 부분 문자열을 바꾸거나 제거하는 다양한 방법을 보여줍니다.
class ReplaceSubstrings { string searchFor; string replaceWith; static void Main(string[] args) { ReplaceSubstrings app = new ReplaceSubstrings(); string s = "The mountains are behind the clouds today."; // String.Replace 로 하나의 부분 문자열을 다른 문자열로 바꿀 수 있습니다. // 정확한 일치만 지원합니다. s = s.Replace("mountains", "peaks"); Console.WriteLine(s); // 결과: The peaks are behind the clouds today. // 보다 더 유연성을 원한다면 Regex.Replace 사용하라. // "the" 또는 "The" 를 "many" 또는 "Many" 로 교체 // System.Text.RegularExpressions 를 사용 app.searchFor = "the"; // A very simple regular expression. app.replaceWith = "many"; s = Regex.Replace(s, app.searchFor, app.ReplaceMatchCase, RegexOptions.IgnoreCase); Console.WriteLine(s); // 결과: Many peaks are behind many clouds today. // 한개의 문자와 일치하는 모든 것을 다른 문자료 교체 s = s.Replace(' ', '_'); Console.WriteLine(s); // 결과: Many_peaks_are_behind_many_clouds_today. // 문자열의 중간에서 부분 문자열을 제거 string temp = "many_"; int i = s.IndexOf(temp); if (i >= 0) { s = s.Remove(i, temp.Length); } Console.WriteLine(s); // 결과: Many_peaks_are_behind_clouds_today. // 뒤나 앞의 공백 제거 // TrimStart 와 TrimEnd 참조 string s2 = " I'm wider than I need to be. "; // 새 문자열 변수의 결과를 저장 temp = s2.Trim(); Console.WriteLine(temp); // 결과: I'm wider than I need to be. // 디버그에서 콘솔창을 열어논 채로 유지 Console.WriteLine("Press any key to exit"); Console.ReadKey(); } // Regex.Replace 에 의해 호출되는 커스텀 매치 메소드 // System.Text.RegularExpressions 사용 string ReplaceMatchCase(Match m) { // 일치 문자가 대문자인지 검사 if (Char.IsUpper(m.Value[0]) == true) { // 교체 문자를 대문자로 변경 // System.Text 사용 StringBuilder sb = new StringBuilder(replaceWith); sb[0] = (Char.ToUpper(sb[0])); return sb.ToString(); } else { return replaceWith; } } }
class ModifyStrings { static void Main() { string str = "The quick brown fox jumped over the fence"; System.Console.WriteLine(str); char[] chars = str.ToCharArray(); int animalIndex = str.IndexOf("fox"); if (animalIndex != -1) { chars[animalIndex++] = 'c'; chars[animalIndex++] = 'a'; chars[animalIndex] = 't'; } string str2 = new string(chars); System.Console.WriteLine(str2); // 디버그 모드에서 콘솔 창을 열린 상태로 유지 System.Console.WriteLine("Press any key to exit."); System.Console.ReadKey(); } } /* 결과: The quick brown fox jumped over the fence The quick brown cat jumped over the fence */
14. 다음 예제에서는 C 스타일의 문자 배열과 유사한 방식으로 안전하지 않은 코드를 사용하여 문자열을 내부적으로 수정해야 하는 매우 드문 경우를 보여줍니다.
15. 이 예제에서는 fixed 키워드를 사용하여 개별 문자에 내부적으로 액세스하는 방법을 보여줍니다.
16. 또한 C# 컴파일러가 내부적으로 문자열을 저장하는 방식 때문에 문자열에 대한 안전하지 않은 작업에서 발생할 수 있는 부작용에 대해서도 설명합니다.
17. 일반적으로 반드시 필요한 경우가 아니라면 이 방법을 사용하새는 안 됩니다.
class UnsafeString { unsafe static void Main(string[] args) { // 컴파일러는 이 문자열들을 같은 위지에 저장합니다. string s1 = "Hello"; string s2 = "Hello"; // 안전하지 않은 코드를 사용하여 한개의 문자열을 바꿉니다. fixed (char* p = s1) { p[0] = 'C'; } // 두 문자열이 변경되었습니다. Console.WriteLine(s1); Console.WriteLine(s2); // 디버그 모드에서 콘솔 창을 열린 채로 유지합니다. Console.WriteLine("Press any key to exit."); Console.ReadKey(); } }
여러 문자열 연결
1. 연결(Concatenation)은 한 문자열을 다른 문자열의 끝에 추가하는 프로세스입니다.
2. + 연산자를 사용하여 문자열 리터럴이나 문자열 상수를 연결하면 컴파일러가 단일 문자열을 생성합니다.
3. 런타임 연결은 발생하지 않습니다.
4. 하지만 문자열 변수는 런타임에만 연결할 수 있습니다.
5. 이 경우 다양한 접근 방식이 성능에 미치는 영향을 이해해야 합니다.
6. 다음 예제에서는 긴 문자열을 더 짧은 문자열로 분할하여 소스 코드의 가독성을 향상시키는 방법을 보여줍니다.
7. 분할된 문자열은 컴파일 타임에 단일 문자열로 연결됩니다.
8. 문자열의 수에 따른 런타임 성능에는 영향이 없습니다.
static void Main() { // 리터럴들의 연결은 런타임이 아니라 컴파일 타임에 수행됩니다. string text = "Historically, the world of data and the world of objects " + "have not been well integrated. Programmers work in C# or Visual Basic " + "and also in SQL or XQuery. On the one side are concepts such as classes, " + "objects, fields, inheritance, and .NET Framework APIs. On the other side " + "are tables, columns, rows, nodes, and separate languages for dealing with " + "them. Data types often require translation between the two worlds; there are " + "different standard functions. Because the object world has no notion of query, a " + "query can only be represented as a string without compile-time type checking or " + "IntelliSense support in the IDE. Transferring data from SQL tables or XML trees to " + "objects in memory is often tedious and error-prone."; Console.WriteLine(text); }
9. 문자열 변수를 연결하려면 + 또는 += 연산자를 사용하거나 String.Concat 또는 String.Format 또는 StringBuilder.Append 메서드를 사용할 수 있습니다.
10. + 연산자는 사용하기 쉽고 가독성을 높여 줍니다.
11. 한 문장에서 + 연산자를 여러개 사용해도 문자열 내용은 한 번만 복사됩니다.
12. 그러나 반복문 등에서 이 연산을 여러 번 반복하면 효율성이 저하될 수도 있습니다. 다음 예제를 참조하세요.
static void Main(string[] args) { // 이 프로그램을 실행하고 커맨드 라인 스트링을 제공하려면 // Visual Studio 에서, Project > Properties > Debug 을 참조하세요. string userName = args[0]; string date = DateTime.Today.ToShortDateString(); // 한번의 결합을 위해서 + 와 += 연산자를 을 사용 string str = "Hello " + userName + ". Today is " + date + "."; System.Console.WriteLine(str); str += " How are you today?"; System.Console.WriteLine(str); // 디버그 모드에서 콘솔 창을 연린 채로 유지합니다. Console.WriteLine("Press any key to exit."); Console.ReadKey(); } // Example output: // Hello Alexander. Today is 1/22/2008. // Hello Alexander. Today is 1/22/2008. How are you today? // Press any key to exit. //
참고
|
13. 루프에서와 같이 많은 수의 문자열을 연결하는 경우가 아니라면 이 코드의 성능 비용은 그리 크지 않을 것입니다. String.Concat 과 String.Format 메서드도 같습니다.
14. 하지만 성능이 중요한 경우에는 항상 StringBuilder 클래스를 사용하여 문자열을 연결해야 합니다.
15. 다음 코드에서는 + 연산자와 같은 성능 영향이 없는 StringBuilder 클래스의 Append 메서드를 사용하여 문자열을 연결합니다.
class StringBuilderTest { static void Main() { string text = null; // 타이트한 루프에서 연결은 StringBuilder 을 사용 System.Text.StringBuilder sb = new System.Text.StringBuilder(); for (int i = 0; i < 100; i++) { sb.AppendLine(i.ToString()); } System.Console.WriteLine(sb.ToString()); // 디버그 모드에서 콘솔 창을 열린 채로 유지 System.Console.WriteLine("Press any key to exit."); System.Console.ReadKey(); } } // Output: // 0 // 1 // 2 // 3 // 4 // ... //
문자열 비교
1. 문자열을 비교할 경우 한 문자열이 다른 문자열보다 크거나 작거나 같다는 결과를 얻게 됩니다.
2. 결과를 결정하는 규칙은 서수 비교를 수행하는지, 문화권 구분 비교를 수행하는지에 따라 달라집니다.
3. 언어 규칙을 고려하지 않고 두 문자열 값을 비교하거나 정렬해야 하는 경우 기본 서수 비교를 사용합니다.
4. 기본 서수 비교(System.StringComparison.Ordinal)는 대/소문자를 구분합니다. 예를 들어, "and", "And", "AND"가 서로 다릅니다.
5. 자주 사용하는 변형으로 System.StringComparison.OrdinalIgnoreCase 가 있는데, 이 경우에는 "and", "And", "AND"가 서로 같습니다.
6. System.StringComparison.OrdinalIgnoreCase 는 파일 이름, 경로 이름, 네트워크 경로 및 사용자 컴퓨터의 로캘에 따라 값이 변경되지 않는 기타 문자열을 비교할 때 자주 사용됩니다.
7. 일반적으로 문화권 구분 비교는 최종 사용자가 입력한 문자열을 비교하고 정렬할 때 사용됩니다.
8. 이것은 이러한 문자열의 문자 및 정렬 규칙이 사용자 컴퓨터의 로캘에 따라 달라질 수 있기 때문입니다.
9. 현재 스레드의 문화권에 따라 동일한 문자를 포함하는 문자열도 다르게 정렬될 수 있습니다.
참고 |
---|
// Internal strings that will never be localized. string root = @"C:\users"; string root2 = @"C:\Users"; // Use the overload of the Equals method that specifies a StringComparison. // Ordinal is the fastest way to compare two strings. bool result = root.Equals(root2, StringComparison.Ordinal); Console.WriteLine("Ordinal comparison: {0} and {1} are {2}", root, root2, result ? "equal." : "not equal."); // To ignore case means "user" equals "User". This is the same as using // String.ToUpperInvariant on each string and then performing an ordinal comparison. result = root.Equals(root2, StringComparison.OrdinalIgnoreCase); Console.WriteLine("Ordinal ignore case: {0} and {1} are {2}", root, root2, result ? "equal." : "not equal."); // A static method is also available. bool areEqual = String.Equals(root, root2, StringComparison.Ordinal); // String interning. Are these really two distinct objects? string a = "The computer ate my source code."; string b = "The computer ate my source code."; // ReferenceEquals returns true if both objects // point to the same location in memory. if (String.ReferenceEquals(a, b)) Console.WriteLine("a and b are interned."); else Console.WriteLine("a and b are not interned."); // Use String.Copy method to avoid interning. string c = String.Copy(a); if (String.ReferenceEquals(a, c)) Console.WriteLine("a and c are interned."); else Console.WriteLine("a and c are not interned."); // Output: // Ordinal comparison: C:\users and C:\Users are not equal. // Ordinal ignore case: C:\users and C:\Users are equal. // a and b are interned. // a and c are not interned.
10. 다음 예제는 StringComparison 열거형을 사용하는 System.String 메서드를 통해 원하는 방식으로 문자열을 비교하는 방법을 보여줍니다.
11. String.CompareTo 인스턴스 메서드는 해당 오버로드가 StringComparison을 사용하지 않으므로 이 예제에 사용되지 않습니다.
// "They dance in the street." // Linguistically (in Windows), "ss" is equal to // the German essetz: 'ß' character in both en-US and de-DE cultures. string first = "Sie tanzen in die Straße."; string second = "Sie tanzen in die Strasse."; Console.WriteLine("First sentence is {0}", first); Console.WriteLine("Second sentence is {0}", second); // Store CultureInfo for the current culture. Note that the original culture // can be set and retrieved on the current thread object. System.Threading.Thread thread = System.Threading.Thread.CurrentThread; System.Globalization.CultureInfo originalCulture = thread.CurrentCulture; // Set the culture to en-US. thread.CurrentCulture = new System.Globalization.CultureInfo("en-US"); // For culture-sensitive comparisons, use the String.Compare // overload that takes a StringComparison value. int i = String.Compare(first, second, StringComparison.CurrentCulture); Console.WriteLine("Comparing in {0} returns {1}.", originalCulture.Name, i); // Change the current culture to Deutch-Deutchland. thread.CurrentCulture = new System.Globalization.CultureInfo("de-DE"); i = String.Compare(first, second, StringComparison.CurrentCulture); Console.WriteLine("Comparing in {0} returns {1}.", thread.CurrentCulture.Name, i); // For culture-sensitive string equality, use either StringCompare as above // or the String.Equals overload that takes a StringComparison value. thread.CurrentCulture = originalCulture; bool b = String.Equals(first, second, StringComparison.CurrentCulture); Console.WriteLine("The two strings {0} equal.", b == true ? "are" : "are not"); /* * Output: First sentence is Sie tanzen in die Straße. Second sentence is Sie tanzen in die Strasse. Comparing in en-US returns 0. Comparing in de-DE returns 0. The two strings are equal. */
12. 다음 예제에서는 System.StringComparer 매개 변수를 사용하는 정적 Array 메서드를 통해 문화권 구분 방식으로 배열에서 문자열을 정렬하고 검색하는 방법을 보여줍니다.
class SortStringArrays { static void Main() { string[] lines = new string[] { @"c:\public\textfile.txt", @"c:\public\textFile.TXT", @"c:\public\Text.txt", @"c:\public\testfile2.txt" }; Console.WriteLine("Non-sorted order:"); foreach (string s in lines) { Console.WriteLine(" {0}", s); } Console.WriteLine("\n\rSorted order:"); // Specify Ordinal to demonstrate the different behavior. Array.Sort(lines, StringComparer.Ordinal); foreach (string s in lines) { Console.WriteLine(" {0}", s); } string searchString = @"c:\public\TEXTFILE.TXT"; Console.WriteLine("Binary search for {0}", searchString); int result = Array.BinarySearch(lines, searchString, StringComparer.OrdinalIgnoreCase); ShowWhere<string>(lines, result); //Console.WriteLine("{0} {1}", result > 0 ? "Found" : "Did not find", searchString); // Keep the console window open in debug mode. System.Console.WriteLine("Press any key to exit."); System.Console.ReadKey(); } // Displays where the string was found, or, if not found, // where it would have been located. private static void ShowWhere<T>(T[] array, int index) { if (index < 0) { // If the index is negative, it represents the bitwise // complement of the next larger element in the array. index = ~index; Console.Write("Not found. Sorts between: "); if (index == 0) Console.Write("beginning of array and "); else Console.Write("{0} and ", array[index - 1]); if (index == array.Length) Console.WriteLine("end of array."); else Console.WriteLine("{0}.", array[index]); } else { Console.WriteLine("Found at index {0}.", index); } } } /* * Output: Non-sorted order: c:\public\textfile.txt c:\public\textFile.TXT c:\public\Text.txt c:\public\testfile2.txt Sorted order: c:\public\Text.txt c:\public\testfile2.txt c:\public\textFile.TXT c:\public\textfile.txt Binary search for c:\public\TEXTFILE.TXT Found at index 2. */
13. System.Collections.Hashtable, System.Collections.GenericDictonary<TKey, TValue> 및 System.Collections.Generic.List<T> 등의 컬렉션 클래스에는 요소나 키의 형식이 string일 경우 System.StringComparer 매개 변수를 사용하는 생성자가 있습니다.
14. 일반적으로 가능한 경우에는 항상 이러한 생성자를 사용하여 Ordinal 또는 OrdinalIgnoreCase를 지정해야 합니다.
String.Split를 사용하여 문자열 구분 분석
1. 다음 코드 예제에서는 String.Split 메서드를 사용하여 문자열을구문 분석하는 방법을 보여줍니다.
2. Split는 대상 문자열의 흥미로운 하위 문자열을 구문 분석하는 문자를나타내는 문자 배열을 입력으로 사용합니다.
3. 함수는 하위 문자열 배열을 반환합니다.
4. 이 예제에서는 공백, 쉼표, 마침표, 콜론 및 탭을 사용하며, 모두 이러한 구분 문자를 포함하는 배열로 Split에 전달됩니다. 대상 문자열 문자의 각 단어는 결과 문자열 배열과 별도로 표시됩니다.
class TestStringSplit { static void Main() { char[] delimiterChars = { ' ', ',', '.', ':', '\t' }; string text = "one\ttwo three:four,five six seven"; System.Console.WriteLine("Original text: '{0}'", text); string[] words = text.Split(delimiterChars); System.Console.WriteLine("{0} words in text:", words.Length); foreach (string s in words) { System.Console.WriteLine(s); } // Keep the console window open in debug mode. System.Console.WriteLine("Press any key to exit."); System.Console.ReadKey(); } } /* Output: Original text: 'one two three:four,five six seven' 7 words in text: one two three four five six seven */
5. 기본적으로 String.Split는 두 구분 문자가 대상 문자열에 연속적으로 표시되는 경우 빈 문자열을 반환합니다.
6. 선택적 StringSplitOptions.RemoveEmptyentries 매개 변수를 전달하여 출력에서 빈 문자열을 모두 제외할 수 있습니다.
7. String.Split는 문자열배열(단일 문자 대신 대상 문자열을 구문 분석하기 위한 구분 기호 역할을하는 문자시퀀스)을 사용할 수 있습니다.
class TestStringSplit{
static void Main(){
char[] separatingChars = { "<<", "..." };string text = "one<<two......three<four";System.Console.WriteLine("Original text: '{0}'", text);
string[] words = text.Split(separatingChars, System.StringSplitOptions.RemoveEmptyEntries );System.Console.WriteLine("{0} substrings in text:", words.Length);
foreach (string s in words){System.Console.WriteLine(s);}// Keep the console window open in debug mode.
System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
}
}
/* Output:
Original text: 'one<<two......three<four' 3 words in text: one two three<four
*/
문자열에서 일치하는 단어의 수 세기 (LINQ)
1. 이 예제에서는 LINQ 쿼리를 사용하여 한 문자열에서 지정한 단어가 나오는 횟수를 세는 방법을 보여줍니다.
2. 횟수를 세개 위해 먼저 Split 메서드를 호출하여 단어 배열을 만듭니다.
3. Split 메서드는 성능 저하가 있습니다.
4. 단어의 횟수만을 세는 경우라면 대신 Matches 또는 IndexOf 메서드를 사용하는 것이 좋습니다.
5. 그러나 성능이 중요한 문제가 아니거나 문장에 대해 다른 쿼리 형식을 수행하기 위해 해당 문장으르 이미 분할한 경우 LINQ를 사용하여 단어나 구가 나오는 횟수를 계산할 수도 있습니다.
class CountWords { static void Main() { string text = @"Historically, the world of data and the world of objects" + @" have not been well integrated. Programmers work in C# or Visual Basic" + @" and also in SQL or XQuery. On the one side are concepts such as classes," + @" objects, fields, inheritance, and .NET Framework APIs. On the other side" + @" are tables, columns, rows, nodes, and separate languages for dealing with" + @" them. Data types often require translation between the two worlds; there are" + @" different standard functions. Because the object world has no notion of query, a" + @" query can only be represented as a string without compile-time type checking or" + @" IntelliSense support in the IDE. Transferring data from SQL tables or XML trees to" + @" objects in memory is often tedious and error-prone."; string searchTerm = "data"; // 문자열을 단어 배열로 변환 string[] source = text.Split(new char[] { '.', '?', '!', ' ', ';', ':', ',' }, StringSplitOptions.RemoveEmptyEntries); // 쿼리를 만들고 'data'와 'Data'와 를 찾기 위해서 ToLowerInvariant 메서드를 사용합니다. var matchQuery = from word in source where word.ToLowerInvariant() == searchTerm.ToLowerInvariant() select word; // 쿼리를 실행해서 일치하는 단어의 개수를 셉니다. int wordCount = matchQuery.Count(); Console.WriteLine("{0} 개의 일치 일치 \"{1}\" 가 발견됨.", wordCount, searchTerm); // Keep console window open in debug mode Console.WriteLine("Press any key to exit"); Console.ReadKey(); } } /* Output: 3 개의 일치 "data" 가 발견됨
*/
var
1. Visual C# 3.0 부터는 메서드 범위에서 선언된 변수가 암시적(implicit) 형식 var를 가질 수 있습니다.
2. 암시적으로 형식이 지정된 지역 변수는 형식을 직접 지정한 것처럼 강하게 형식이 지정되었지만 컴파일러가 형식을 결정합니다.
3. 다음의 i의 두 선언은 기능면에서 동일합니다.
var i = 10; // 암시적으로 형식이 지정됨
int i = 10; // 명시적으로 형식이 지정됨
4. 다음 예제에서는 두 개의 쿼리 식을 보여줍니다.
5. 첫번째 식에서 var 의 사용은 허용되나 필수는 아닙니다. 왜냐하면 쿼리 결과가 IEnumerable<string>에서 명확하게 시작되기 때문입니다.
6. 두번째 식에서 var는 필수입니다. 왜냐하면 결과가 익명 형식의 컬렉션이고 그 형식의 이름은 컴파일러 자체 이왜에는 액세스할 수 없기 때문입니다.
7. 예제의 foreach 반복 변수 item 은 암시적으로 형식이 지정되어야 합니다.
// 예제 #1: var 는 선택적이다. // select 절이 문자열을 가리키고 있기 때문이다. string[] words = { "apple", "strawberry", "grape", "peach", "banana" }; var wordQuery = from word in words where word[0] == 'g' select word; // 각 요소는 익명 형식이 아니라 문자열이기 때문에 또한 var는 선택적이다. foreach (string s in wordQuery) { Console.WriteLine(s); } // 예제 #2: var 는 필수이다. // 왜냐하면 select 절이 익명 형식을 기리키고 있기 때문이다. var custQuery = from cust in customers where cust.City == "Phoenix" select new { cust.Name, cust.Phone }; // var 는 필수이다. // 왜냐하면 각각의 item이 익명 형식이기 때문이다. foreach (var item in custQuery) { Console.WriteLine("Name={0}, Phone={1}", item.Name, item.Phone); }
'프로그래밍 > C#' 카테고리의 다른 글
C# 키워드 O~S (0) | 2016.05.31 |
---|---|
C# 키워드 F~N (0) | 2016.05.21 |
C# 키워드 A-E (0) | 2016.05.13 |
연산자 2 (0) | 2016.05.10 |
정리 (0) | 2016.04.09 |