C#을 배워보자 (3) - 배열, 조건문, 반복문

김영현·2024년 11월 19일
0

C#

목록 보기
3/5

배열

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 - case

switch (expression){
	case value1:
    ...
    break;
    
    case value2:
    ...
    break;
    
    default:
    ...
    break;
}

조건을 지정할 표현식을 switch문에 넣고, case별로 조건을 지정한다.
어떤 조건에도 해당되지 않는다면 default에 작성된 값이 반환됨.

Early return

조건문의 중첩이 생길때 보기 쉽게 풀어낼 수 있는 디자인 패턴 중 하나

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/


반복문

특정부분 코드를 반복실행 시켜야할 때 사용함.

while

whlie(condtion){
	...
    break //while문 종료
}

참고로 C#은 모든 코드가 함수 내에 있다. 따라서 return을 잘못 사용시 함수가 종료되니 유의하여야 함

do-while

while은 조건이 참일때만 돌아가지만, do-while은 한번 실행되고 조건을 탐색한다.

for

js에서는 forEach, for...of, Array.prototype.map등 선언적으로 사용할 수 있는 메서드가 많아서 자주 사용하진 않았다.

for(int i = 0; i<6; ++i){
	...
}

템플릿은 똑같다

foreach

놀랍게도 카멜케이스가 아니다...😮

string[] fruits = {"바나나", "사과", "파인애플", ...};

foreach(string fruit in fruits){
	Console.WriteLine(fruit);
}

js의 Array.prototype.forEach()Arrayiteration protocol을 구현하여서 순회 가능한 구조가 되었다.

C#도 마찬가지로 IEnumerable인터페이스를 구현하였기에 foreach(...)같은 이터레이션을 사용할 수 있다.


번외) IEnumerable

js에서 객체를 순회하는 방법을 보자.

이렇게 for..in을 사용할 수도 있다. 하지만 이는 를 열거하는 것 뿐이지, 정확히는 값을 순회하는 게 아니다.

만약 for...of처럼 값을 순회하고 싶다면, iteration protocol을 준수해야한다.

C#도 그렇다. C#에서 객체를 foreach(...)로 순회하고 싶다면, foreach(...)와의 약속을 지켜야한다. 즉, IEnumerable인터페이스를 준수해야한다.

IEnumerable는 하나의 메서드를 반환한다.

public interface IEnumerable
{
    IEnumerator GetEnumerator();
}

GetEnumrator로 반환된 Enumrator는 아래와 같은 속성, 메서드를 가진다.

js에서 알게된 iteration protocol을 준수한 이터러블과 유사하다. valuedone프로퍼티!

그렇다면 IEnumerable인터페이스를 준수한 객체를 만들어보자.

IEnumrable 구현

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

profile
모르는 것을 모른다고 하기

0개의 댓글