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);
}
}
댓글남기기