System.Index #1
int: Sequnces 접근을 위한 값만 보관
System.Index: Sequence접근을 위한 값과 방향을 보관
using System; class Program { static void Main(string[] args) { int[] arr={1,2,3,4,5,6,7,8,9,10}; int n1=arr[2]; //3 int n2=arr[^2]; //뒤에서부터 2번째(제로베이스가아님). =>9 Console.WriteLine($"{n1}, {n2}"); } }
인덱스 접근. ^2는 뒤에서부터 2번째를 의미하는데 사실 index객체를 만드는게 숨겨져있다.
using System; class Program { static void Main(string[] args) { string s ="ABCDEFGHI"; //# Sequence 요소에 접근하기위한 인덱스만들기 int indx1=2; Index idx2 = new Index(2); //Index idx3 = new Index(2,true); //뒤에서 두번째 Index idx3 = new Index(2,fromEnd:true); //뒤에서 두번째 char c1= s[idx1]; //c char c2= s[idx2]; //c char c3= s[idx3]; //h Console.WriteLine($"{c1}"); } }
인덱스 객체를 명시적으로 만들어서 사용하는 방법.
Index객체를 만드는방법(3가지방법)
class Program { static void Main(string[] args) { //Index 객체 만들기1. new 사용 Index i1 = new Index(3); Index i2 = new Index(3,fromEnd:true); //Index 객체 만들기2. 정적메소드 사용 Index i3 = Index.FromStart(3); Index i4 = Index.FromEnd(3); //Index 객체 만들기3. 단축표기법 사용 Index i5 = 3 Index i6 = ^3; } }
Value/IsFromEnd 속성
class Program { static void Main(string[] args) { Index idx=^3; int n=idx.Value; //3 bool b=idx.isFromEnd; //true } }
System.Index #2
사용자 정의 타입과 index
using System; class Sentence { private string[] words=null; public Sentence(string s) {words=s.Split();} public string this[int idx] {get{return words[idx];}} //indexer 문법 public string this[Index idx] {get{return words[idx];}} //indexer 문법 } class Program { static void Main(string[] args) { Sentence sen= new Sentence("C# Program Study"); string s2 =sen[1]; //indexer필요 string s2=sen[^1]; //indexer에 Index를 받는것도 구현필요. } }
인덱서 구현시 인덱스객체를 사용하려면 Index를 받는것도 구현하여야 한다.
다만, 인덱스구현없이도 구현하는 방법이 존재한다.
아래 코드를 참고하자.
컴파일러는 Length/Count 를 찾기때문에 이를 구현하면 Index를 위한 Indexer를 굳이 구현하지않아도된다.
using System; class Sentence { private string[] words=null; public Sentence(string s) {words=s.Split();} public string this[int idx] {get{return words[idx];}} //public string this[Index idx] {get{return words[idx];}} public int Length {get{return words.Length}} } class Program { static void Main(string[] args) { Sentence sen= new Sentence("C# Program Study"); string s2 =sen[1]; string s2=sen[^1]; //error : 컴파일러=> 1. this[Index] 검색/ 2. sen[sen.Length-1] 검색 3. sen[sen.Count-1]검색 } }
즉, 사용자 정의 컬렉션에 “Index를 지원”하게 하려면 - 방법1. Index를 인자로 가지는 인덱서 제공 - 방법2. Length또는 Count 속성 제공
System.Range
C# 8.0 에 추가된 기능이다. 파이썬등 최근언어에서는 자주 쓰이는 문법으로 구간을 나타내는 타입이다.
using System; class Program { static void Main(string[] args) { string s1 ="ABCDEFGHIJ"; char c= s1[2]; //C string s2=s1[2..7]; //CDEFG //뒤에꺼는 포함안됨. string s3=s1[2..^3]; //CDEFG Console.WriteLine($"{c},{s2},{s3}"); } }
.., ^등 으로 나타낼수있다.
System.Range:
2개의 인덱스를 가지고 하나의 구간을 나타내는 타입으로 객체를 만들어서 사용하는것도 가능하다.
using System; class Program { static void Main(string[] args) { int[] arr1={1,2,3,4,5,6,7,8,9,10}; //C# 8.0에서 추가된 System.Range //Range r1=new Range(); Range r1=new Range(new Index(2),new Index(2,true)); //3-8 Range r2 =new Range(2,^2); //위와동일 Range r1 =2..^2 //위와 동일한 표기법. int[] arr2=arr1[r1] foreach(var n in arr2) Console.WriteLine($"{n}"); } }
인덱스와 마찬가지로 표기하는 방법은 여러가지이다. 단축표기를 사용하거나 range객체를 만들어서 표현할수있다.
using System; class Program { static void Main(string[] args) { string s1 ="ABCDEFGHIJ"; //1. new 사용 Range r1 =new Range(); Range r2=new Range(2,^2); //2.정적 메소드 사용 Range r3 =Range.All;//ABCDEFGHIJ Range r4=Range.StartAt(4);//EFGHIJ Range r5=Range.EndAt(4); //ABCD //3.단축표기법 Range r6 =2..7; Range r7=2..^2; Range r8=..4; //ABCD Range r9=4..; //EFGHIJ Console.WriteLine($"{c},{s2},{s3}"); } }
Range를 사용하는 여러가지 방법.
Pattern Matching
임의 개체가 특정패턴(모양,타입,값)을 만족하는지 조사하는것.
“r타입은 Rect타입인가? r은 정사각형인가? r의 x좌표는 10인가”
- type pattern matching : c#초기부터 지원. 7.0에서 기능추가
- var pattern matching :c# 7.0
- const pattern matching: c#7.0
- switch expression :c#8.0
using System; class Shape { } class Circle : Shape { public double radius = 100; } class Program { public static void Draw(Shape s) { /* //전통적인 is연산자. if ( s is Circle ) { Circle c1 = (Circle)s; double d = c1.radius; } */ //C# 7.0에서 추가된 새로운 표기법 //if(객체 is 타입 변수) if (s is Circle c1) { double d = c1.radius; } // var pattern matching if (s is var c2) // var c2 = s { } } static void Main() { Draw(new Circle()); } }
c# 7.0 에서 추가된 새로운 표기법을 확인.
using System; class Circle { } class Program { public static void Main() { object o = new Circle(); if ( o is Circle c1) { } // type pattern matching if ( o is var c2) { } // var pattern matching int n = 10; if ( n is 10 ) // const pattern matching { } if ( n == 10 ) { } object obj = 10; //if ( obj == 10 ) // error //if (obj == (object)10) // ok =>그러나 False. 참조변수 두개를 비교하면 값이 같은지 비교x if ((int)obj == 10) //unboxing해서 값비교 { //Console.WriteLine("True"); } //else //Console.WriteLine("False"); if ( obj is 10) //요것도 unboxing해서 값비교하는것과 동일하게된다. { } } }
const/type/var 패턴매칭을 비교하여 확인. is 연산자를 사용할경우에 참조변수의 값을 언박싱해서 비교할수있다.
Switch와 패턴매칭
using System; class Shape { } class Circle : Shape { } class Rectangle : Shape { public double width = 100; public double height = 100; } class Program { public static void Draw(Shape s) { switch (s) { // const pattern matching case null: break; // type pattern matching case Circle c: break; case Rectangle r when r.width == r.height: break; case Rectangle r: break; default: break; } } public static void Main() { Draw(new Rectangle()); //# 전통적인 switch 문의 구조 int n = 1; switch (n) { case 1: break; case 2: break; default: break; } } }
using System; using System.Collections.Generic; class Shape { } class Circle : Shape { } class Rectangle : Shape { public double width = 100; public double height = 100; } class Program { public static List<Shape> group = new List<Shape>(); public static void Draw(Shape s) { switch (s) { case var r when (group.Contains(r)) : break; case Rectangle r: break; default: break; } } public static void Main() { Draw(new Rectangle()); } }
Switch Expression
Statement(문,문장)
- 프로그램을 구성하는 기본요소
- C#에서 하나의 문장은 ;로 종료된다.
- 언어에 따라 정의가 약간 다르다.
expression(표현식)
- 대부분의 언어가 유사한 정의를 사용.
- 하나의 값으로 계산되는식
- 연산자와 피연산자로 구성된다.
- return을 표기하지않아도 하나의 값으로 반환된다.
using System; class Program { public int square(int n) { return n * n; } public int square2(int n) => n * n; //expression public static void Main() { int n = 50; //int s = n switch { 10 => 11, 20 => 22, 30 => 33, _ => 100 }; int s = n switch { 10 => 11, 20 => 22, 30 => 33, _ => 100 }; Console.WriteLine(s); int k = 2 * 3 + 4 - n; //# 일반적인 switch 문의 구조 ( switch statement ) switch(n) { case 10: break; case 20: break; default: break; } } }
using System; class Shape { } class Rectangle : Shape { public double Width { set; get; } = 10; public double Height { set; get; } = 10; } class Circle : Shape { public double Radius { set; get; } = 10; } class Point : Shape { public double x = 0; public double y = 0; public void Deconstruct(out double ox, out double oy) => (ox, oy) = (x, y); } class Program { public static void Main() { Shape s = new Circle(); // type pattern matching double area = s switch { null => 0, // const pattern matching Point _ => 0, Circle c => Math.PI * c.Radius * c.Radius, Rectangle r => r.Width * r.Height, _ => 0 }; // tuple pattern int value1 = 0; int value2 = 0; var ret1 = (value1, value2) switch { (0, 0) => 0, var (a, b) when a > 100 => 100, var (a, b) when a <= 100 && b > 100 => 200, _ => 300 }; // positional pattern : Deconstructor 가 있는 타입 Point pt = new Point(); var (x1, y1) = pt; var ret2 = pt switch { (0, 0) => 0, var (a, b) when a > 100 => 100, var (a, b) when a <= 100 && b > 100 => 200, _ => 300 }; } }
Local Function
Local Function: 메소드안에 다시 메소드를 만드는 문법
- 자신이 포함된 메소드안에서만 호출할수있다.
오류처리와 함수구현부를 분리할때 주로 사용
- iterator를 만들거나 비동기 메소드에서 주로 사용.
using System; class Program { public static void Foo() { int n = square(3); int square(int a) { return a * a; } } /* public static double div(double a, double b) { if (b == 0) throw new Exception("divide by zero"); return a / b; } */ /* public static double div(double a, double b) { return a / b; } */ public static double div_wrapper(double a, double b) { if (b == 0) throw new Exception("divide by zero"); return div(a, b); double div(double a, double b) { return a / b; } } public static void Main() { double ret = div_wrapper(10, 0); Console.WriteLine(ret); } }
- 실제 사용하는 예제.
using System; using System.Collections; // 1 ~ 5 까지의 숫자를 보관하는 컬렉션 class NumCollections : IEnumerable { private int[] arr = new int[5] { 1, 2, 3, 4, 5 }; public IEnumerator GetEnumerator() { // 오류만 확인.. Console.WriteLine("arr 의 유효성 확인"); if (arr == null) throw new Exception("null"); return implementation(); IEnumerator implementation() { foreach (int n in arr) { yield return n; } } } } class Program { public static void Main() { NumCollections nums = new NumCollections(); IEnumerator it = nums.GetEnumerator(); Console.WriteLine("After GetEnumerator"); while( it.MoveNext() ) { Console.WriteLine(it.Current); } } }
using System; class Program { public static int Foo(int a, int b) { int value = 10; return goo(10); static int goo(int n) //C# 8.0 static local fuction =>value,a,b접근불가. { return value + a + b + n; } } public static void Main() { Console.WriteLine(Foo(1, 2)); } }
New Syntax in C# 8.0
디폴트인터페이스 멤버
using System; interface ICamera { void takePicture(); //새롭게 추가된 인터페이스 함수 ->이렇게되면 인터페이스 상속하는 모든 것을 바꿔야함.그래서 인터페이스함수의 구현부를 만듬 void uploadSNS() { Console.WriteLine("upload SNS"); } } class Camera : ICamera { public void takePicture() { Console.WriteLine("Take Picture With Camera"); } public void uploadSNS() { Console.WriteLine("Camera upload SNS"); } } class Program { static void Main() { Camera c = new Camera(); c.takePicture(); c.uploadSNS(); //error ICamera ic = c; ic.uploadSNS(); //사용하려면 인터페이스로 캐스팅해서 사용. } }
인터페이스 함수의 구현부를 만들수있다.
using 선언
using System; using System.IO; using static System.Console; // WriteLine("AA") class Program { static void Main() { FileStream f1 = new FileStream("a1.txt", FileMode.CreateNew); f1.Dispose(); using (FileStream f2 = new FileStream("a2.txt", FileMode.CreateNew)) { } // f2.Dispose } public static void Foo() { //+ C# 8.0 using FileStream f3 = new FileStream("a3.txt", FileMode.CreateNew); } // f3.Dispose() }
using() 으로 묶던것을 그냥 using만 써도 된다.
Nullable Reference
using System; class Program { static void Main() { //int n1 = null; // error //int? n2 = null; // ok #nullable enable // 참조 타입 변수를 null 을 대입하면 경고.. string s1 = null; // ok string? s2 = null; #nullable disable //int n = s1.Length; } }
null병합 대입
using System; class Program { public static void Main() { string s1 = null; //# C# 6.0 NULL 병합 연산자 string s2 = s1 ?? "hello"; //# C# 8.0 NULL 병합 대입 s1 = "hello"; s1 ??= "world"; // if ( s1 == null ) s1 = "world" Console.WriteLine(s1); } }