C#의 배열은 중괄호다. 타입은 대괄호.
string[] arr = { "banana", "apple" };
왜 타입과 초기화할때 괄호 모양이 다를까?
우리의 chat gpt선생의 말에 따르면 그렇다. 사실여부는 나중에 파악해본다...😓
첫 예시처럼 string [] arr...
선언하면 문자열만 들어가는 배열이 된다. 다른 타입은 끼어들 수 없음.
만약 서로 다른타입을 한 배열 내 사용하고싶은경우 아래와 같이 사용할 수 있다.
첫번째는 object
타입을 사용하는 방법.
js의 모든 값이 Object
의 프로토타입을 상속받는 것 처럼, C#도 모든 타입이 object를 상속한다.
따라서 object
를 사용하면 여러 타입을 담을 수 있음.
다만 배열의 길이가 고정되는 단점이 있음.
두번째는 List<object>
를 사용하는 방법. 배열의 길이가 가변적이기에 object[]
를 이용한 방법보다 유연함. 유연한 만큼 메모리 낭비가 있음.
세번째는 타입스크립트에서 커스텀 인터페이스를 활용한 배열 선언처럼, C#에서도 커스텀 인터페이스를 이용하여 배열에 여러 타입을 담을 수있다.
using System;
namespace ConsoleApp1
{
public interface IAnimal
{
void Speak();
}
public class Dog : IAnimal
{
public void Speak() => Console.WriteLine("Woof!");
}
public class Cat : IAnimal
{
public void Speak() => Console.WriteLine("Meow!");
}
class Program
{
static void Main(string[] args)
{
IAnimal[] animals = new IAnimal[]
{
new Dog(),
new Cat()
};
foreach (var animal in animals)
{
animal.Speak();
}
Console.ReadLine();
}
}
}
js에서는 아래와 같이 초기화했다.
//리터럴
const arr = [[],[],[]];
C#는 컴마,
를 사용한다.
int[,] arr = { { 1 }, { 2 } };
위처럼 선언하면 크기가 2x1로 고정되며 column의 모든 길이가 같아야한다.
길이가 다른 가변 배열을 선언하려면 아래처럼 해야한다.
int[][] arr = new int[2][]; //row가 2고 column은 가변인 배열
[][]
나 [,]
로 통일해주면 안될까...?😰
인덱스선택도 마찬가지다. js는 arr[0][0]
이렇게 선택하지만, C#은 arr[0,0]
요래 선택함.
int[,] arr = { {1}, { 2} };
Console.WriteLine(arr[0, 0]);
비교연산자, 조건부논리연산자를 이용하여 코드블럭을 실행시킬 수 있음
if(condition){
//condition이 true일시 실행
} else {
//condition이 false일시 실행
}
switch (expression){
case value1:
...
break;
case value2:
...
break;
default:
...
break;
}
조건을 지정할 표현식을 switch문에 넣고, case별로 조건을 지정한다.
어떤 조건에도 해당되지 않는다면 default에 작성된 값이 반환됨.
조건문의 중첩이 생길때 보기 쉽게 풀어낼 수 있는 디자인 패턴 중 하나
if(success){
login();
...
} else if(permission_denide){
...
} else if(invalid_argument){
...
} else { //validation error
...
}
위와같은 검증 로직을 보기 쉽게 변경해보자
if(validation_error){
return ...
}
if(invalid_argument){
return ...
}
if(permission_denied){
return ...
}
login();
조건문을 작성할때 보통 성공 케이스를 처음 작성하고, 그 다음 실패 케이스를 나열하게된다.
early return은 실패 케이스를 먼저 작성하고, 마지막에 성공케이스를 작성한다.
코드가 선형적으로 작성되어 읽기 쉬운 코드가 된다. 또한, 관리하고 테스트하기 쉬운 함수가 된다.
출처 : https://www.c-sharpcorner.com/article/early-return-pattern-in-c-sharp/
특정부분 코드를 반복실행 시켜야할 때 사용함.
whlie(condtion){
...
break //while문 종료
}
참고로 C#은 모든 코드가 함수 내에 있다. 따라서 return
을 잘못 사용시 함수가 종료되니 유의하여야 함
while
은 조건이 참일때만 돌아가지만, do-while
은 한번 실행되고 조건을 탐색한다.
js에서는 forEach, for...of, Array.prototype.map
등 선언적으로 사용할 수 있는 메서드가 많아서 자주 사용하진 않았다.
for(int i = 0; i<6; ++i){
...
}
템플릿은 똑같다
놀랍게도 카멜케이스가 아니다...😮
string[] fruits = {"바나나", "사과", "파인애플", ...};
foreach(string fruit in fruits){
Console.WriteLine(fruit);
}
js의 Array.prototype.forEach()
는 Array
가 iteration protocol을 구현하여서 순회 가능한 구조가 되었다.
C#도 마찬가지로 IEnumerable인터페이스를 구현하였기에 foreach(...)
같은 이터레이션을 사용할 수 있다.
js에서 객체를 순회하는 방법을 보자.
이렇게 for..in
을 사용할 수도 있다. 하지만 이는 키를 열거하는 것 뿐이지, 정확히는 값을 순회하는 게 아니다.
만약 for...of
처럼 값을 순회하고 싶다면, iteration protocol을 준수해야한다.
C#도 그렇다. C#에서 객체를 foreach(...)
로 순회하고 싶다면, foreach(...)
와의 약속을 지켜야한다. 즉, IEnumerable인터페이스를 준수해야한다.
IEnumerable는 하나의 메서드를 반환한다.
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
GetEnumrator
로 반환된 Enumrator
는 아래와 같은 속성, 메서드를 가진다.
js에서 알게된 iteration protocol을 준수한 이터러블과 유사하다. value
와 done
프로퍼티!
그렇다면 IEnumerable인터페이스를 준수한 객체를 만들어보자.
using System;
using System.Collections;
public class Person
{
public Person(string fName, string lName)
{
this.firstName = fName;
this.lastName = lName;
}
public string firstName;
public string lastName;
}
//IEnumrable을 구현해보자
public class People : IEnumerable
{
private Person[] _people;
public People(Person[] pArray)
{
_people = new Person[pArray.Length];
for (int i = 0; i < pArray.Length; i++)
{
_people[i] = pArray[i];
}
}
// GetEnumrator()메서드를 구현한다.
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)GetEnumerator();
}
//GetEnumrator()메서드는 PeopleEnum인스턴스에 내부멤버인 _people를 넣은 값을 반환한다.
public PeopleEnum GetEnumerator()
{
return new PeopleEnum(_people);
}
}
// IEnumrator도 구현!
public class PeopleEnum : IEnumerator
{
public Person[] _people;
//컬렉션의 현재 위치를 다루는 인덱스다. MoveNext()메서드가 실행되고, 인덱스가 증가된 뒤 값이 반환되기에 0이 아닌 -1부터 시작한다.
int position = -1;
public PeopleEnum(Person[] list)
{
_people = list;
}
//인덱스를 1증가시키고, 현재 인덱스가 배열의 길이보다 작으면 true를 반환한다. 반환한 bool을 가지고 끝임을 판별해야함.
public bool MoveNext()
{
position++;
return (position < _people.Length);
}
//인덱스를 -1로 리셋
public void Reset()
{
position = -1;
}
object IEnumerator.Current
{
get
{
return Current;
}
}
//try-catch를 이용하여 현재 값을 반환한다. MoveNext에서 반환한 bool을 가지고 예외처리를 함.
public Person Current
{
get
{
try
{
return _people[position];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
}
class App
{
static void Main()
{
Person[] peopleArray = new Person[3]
{
new Person("John", "Smith"),
new Person("Jim", "Johnson"),
new Person("Sue", "Rabon"),
};
People peopleList = new People(peopleArray);
foreach (Person p in peopleList)
Console.WriteLine(p.firstName + " " + p.lastName);
}
}
이렇게 foreach
를 객체에서도 사용할 수 있게 되었다.
출처 : https://learn.microsoft.com/ko-kr/dotnet/api/system.collections.ienumerable?view=net-9.0#methods