[멋쟁이사자처럼부트캠프 Unity게임개발 4기] 9일차 : LINQ / 상속

2025. 3. 5. 16:00·공부/부트캠프
728x90

📌 LINQ를 활용한 문자열 배열 정렬 및 검색

string[] names = { "Charile", "Alice", "Bob" };

// 문자열 배열을 정렬
var sortedNames = names.OrderBy(n => n);

//int Identity(int n)
//{
//    return n;
//}

foreach(var name in sortedNames)
{
    Console.WriteLine(name);
}

// 'A'로 시작하는 첫 번째 이름 찾기
var firstName = names.First(n => n.StartsWith("A"));
Console.WriteLine($"First name starting with A: {firstName}");

 

  • OrderBy(n => n)를 사용하여 알파벳순(A~Z)으로 정렬합니다.
    • OrderBy는 LINQ 메서드로, 내부적으로 정렬된 컬렉션을 반환합니다.
    • sortedNames는 정렬된 IEnumerable<string> 형태의 컬렉션을 가지게 됩니다.
  • First(n => n.StartsWith("A"))
    • A로 시작하는 첫 번째 이름을 찾음
    • First()는 조건을 만족하는 첫 번째 요소를 반환하는 LINQ 메서드
    • 만약 A로 시작하는 이름이 없으면 예외(Exception)가 발생합니다.

📌 LINQ 메서드 구문 vs. 쿼리 구문 비교

int[] nums = { 5, 3, 8, 1 };

// 메서드 구문
var sortedMethod = nums.OrderBy(n => n);

// 쿼리 구문
var sortedQuery = from n in nums
                  orderby n
                  select n;

Console.WriteLine("Method syntax: ");
foreach (var n in sortedMethod) Console.WriteLine(n);

Console.WriteLine("Query syntax: ");
foreach (var n in sortedQuery) Console.WriteLine(n);

1️⃣ 메서드 구문(Method Syntax)

  • OrderBy(n => n): nums 배열을 오름차순으로 정렬
  • 람다 표현식(=>)을 활용하여 OrderBy를 적용
  • **LINQ의 확장 메서드(Extension Method)**를 사용

✔ 장점

  • 간결한 코드
  • 체이닝(Chaining) 가능 → 여러 개의 LINQ 메서드를 연결하여 사용 가능

2️⃣ 쿼리 구문(Query Syntax)

  • SQL 스타일의 LINQ 쿼리 표현식
  • from n in nums → nums 배열에서 데이터를 가져옴
  • orderby n → 정렬 수행 (기본적으로 오름차순)
  • select n → 정렬된 값을 선택하여 반환

✔ 장점

  • SQL과 유사하여 직관적인 가독성 제공
  • 복잡한 데이터 조작 시 가독성이 향상됨

📌 LINQ Select()를 활용한 문자열 길이 추출

string[] words = { "apple", "banana", "cherry" };

// Select()를 사용하여 각 단어의 길이를 추출
var lengths = words.Select(w => w.Length);

foreach(var length in lengths)
{
    Console.WriteLine(length);
}

 

  • Select()는 LINQ 메서드로, 컬렉션의 각 요소를 변환하는 데 사용됨
  • w => w.Length:
    • 각 문자열 w의 길이를 가져와 반환
    • 변환 결과: IEnumerable<int> 형태의 컬렉션을 반환

Select()를 사용하면?

기능 설명
데이터 변환 원본 컬렉션을 가공하여 새로운 컬렉션 생성
문자열 길이 추출 각 단어의 .Length 속성을 가져와 숫자로 변환
가독성 간결한 코드로 데이터 변환 가능

📌 여러 알고리즘

1. 합계 구하기 SUM

            int[] data = { 1, 2, 3, 4, 5 };
            int sum = 0;

            foreach (var d in data)
            {
                sum += d;
            }
            Console.WriteLine($"Sum: {sum}"); //15

2. 개수 구하기 Count

//count
int[] data = { 1, 2, 3, 4, 5 };

int count = data.Length;

Console.WriteLine($"Count: {count}");//5

3. 평균 구하기 Average()

int[] data = { 1, 2, 3, 4, 5 };
double avg = data.Average();
Console.WriteLine($"Average: {avg}"); //3

4. 최댓값 구하기 Max()

int[] data = { 10, 3, 5, 2, 8 };
int max = data.Max();
Console.WriteLine($"Max : {max}");//10

5. 최솟값 구하기 Min()

            int[] data = { 55, 66, 48 };
            int min = data.Min();
            Console.WriteLine($"Min : {min}");//48

6. 근삿값 구하기 

배열에서 특정 값에 가장 가까운 값을 찾는 예제

int[] data = { 10, 20, 30, 43, 55 };
int target = 22;
int nearest = data[0];

foreach (var d in data)
{
    if (Math.Abs(d - target) < Math.Abs(nearest - target))
        nearest = d;
}

Console.WriteLine($"Nearest to {target}: {nearest}");//20

Math.Abs() 메서드는 주어진 숫자의 **절댓값(Absolute Value)**을 반환합니다.
절댓값이란 숫자의 부호(+, -)를 제거한 값으로, 음수는 양수로 변환되고 양수는 그대로 유지됩니다

7. 순위 구하기 

순위를 계산하는 방법:

  • 점수가 높은 학생이 낮은 순위를 가져야 함 (예: 1등, 2등, 3등...)
  • 특정 점수보다 더 높은 점수를 가진 개수만큼 순위를 증가시킴.
int[] scores = { 90, 70, 50, 70, 60 };
for (int i = 0; i < scores.Length; i++)
{
    int rank = 1;
    for (int j = 0; j < scores.Length; j++)
    {
        if (scores[j] > scores[i]) rank++;
    }
    Console.WriteLine($"Score: {scores[i]}, Rank:{rank}");
}

i 비교(j) scores[j] > scores[i] 조건 rank 증가 최종 rank
90 70, 50, 70, 60 false 모두 rank = 1 유지 1
70 90, 50, 70, 60 90 > 70 → +1 rank = 2 2
50 90, 70, 70, 60 90 > 50, 70 > 50, 70 > 50, 60 > 50 → +4 rank = 5 5
70 90, 50, 70, 60 90 > 70 → +1 rank = 2 2
         
60 90, 70, 50, 70 90 > 60, 70 > 60, 70 > 60 → +3 rank = 4 4

8. 순서대로 나열하기 : Sort()

int[] data = { 5, 2, 8, 1, 9 };
Array.Sort(data);

foreach (var d in data) Console.WriteLine(d);

9. 특정 값 검색하기

int[] data = { 5, 2, 8, 1, 9 };
int target = 8;
int index = -1;

for(int i=0; i<data.Length; i++)
{
    if (data[i] == target)
    {
        index = i;
        break;
    }
}
Console.WriteLine(index >= 0 ? $"Found at index {index}" : "Not found");
//Found at index 2

10. 그룹화하기 : GroupBy()

//그룹 
string[] fruits = { "apple", "banana", "blueberry", "cherry", "apricot" };

var groups = fruits.GroupBy(f => f[0]);//첫 글자로 그룹화

foreach(var group in groups)
{
    Console.WriteLine($"Key:{group.Key}");
    foreach(var item in group){
        Console.WriteLine($" {item}");
    }
}

 


 📌상속(Inheritance) 개념

// 부모 클래스 (Animal)
class Animal
{
    public string Name { get; set; } // 동물의 이름 속성

    public void Eat()
    {
        Console.WriteLine($"{Name}이(가) 음식을 먹고 있습니다.");
    }
}

// 자식 클래스 (Dog) - Animal 클래스를 상속
class Dog : Animal
{
    public void Bark()
    {
        Console.WriteLine($"{Name}이(가) 멍멍 짖습니다!");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Dog myDog = new Dog(); // Dog 객체 생성
        myDog.Name = "바둑이"; // 부모 클래스(Animal)의 속성 사용
        myDog.Eat(); // 부모 클래스의 메서드 호출 가능
        myDog.Bark(); // 자식 클래스의 메서드 호출
    }
}

✅ 개념 정리

🔹 상속(Inheritance)

  • 부모 클래스(Animal)의 속성과 메서드를 자식 클래스(Dog)가 물려받는 것
  • Dog 클래스는 Animal 클래스를 상속하므로 Name 속성과 Eat() 메서드를 그대로 사용할 수 있음

🔹 상속의 장점

✔ 코드 재사용 → 부모 클래스의 기능을 자식 클래스에서 그대로 활용
✔ 유지보수 용이 → 부모 클래스의 기능을 수정하면 자식 클래스도 반영됨
✔ 확장성 증가 → 자식 클래스에서 기능을 추가하여 새로운 동작을 정의 가능

 

 📌메서드 오버라이딩(Overriding) 개념 정리

✅  오버라이딩(Overriding)이란?

🔹 부모 클래스의 메서드를 자식 클래스에서 재정의하는 기능
🔹 부모 클래스의 메서드를 virtual 키워드로 선언해야 함
🔹 자식 클래스에서는 override 키워드를 사용해 메서드를 재정의함
🔹 부모 클래스의 메서드를 그대로 사용하지 않고, 자식 클래스에 맞게 동작을 변경할 때 사용

 // 부모 클래스 (Animal)
class Animal
{
    public string Name { get; set; }

    // 가상(virtual) 메서드: 자식 클래스에서 오버라이딩 가능
    public virtual void Speak()
    {
        Console.WriteLine("동물이 소리를 냅니다.");
    }
}

// 자식 클래스 (Dog) - Animal 클래스를 상속받음
class Dog : Animal
{
    // 부모 클래스의 Speak() 메서드를 오버라이딩
    public override void Speak()
    {
        Console.WriteLine($"{Name}이(가) 멍멍 짖습니다.");
    }
}

class Program
{
    static void Main(string[] args)
    {
        // 부모 클래스의 인스턴스
        Animal myAnimal = new Animal();
        myAnimal.Name = "동물";
        myAnimal.Speak(); // "동물이 소리를 냅니다."

        // 자식 클래스의 인스턴스
        Dog myDog = new Dog();
        myDog.Name = "강아지";
        myDog.Speak(); // "강아지이(가) 멍멍 짖습니다."
    }
}

✅  오버라이딩을 활용하는 이유

1️⃣ 다형성(Polymorphism) 지원 → 같은 Speak() 메서드를 호출해도 클래스에 따라 다르게 동작
2️⃣ 코드 재사용성 증가 → 부모 클래스의 기본 동작을 유지하면서 특정 부분만 변경 가능
3️⃣ 객체 지향적인 프로그래밍 가능 → 상속 관계를 활용한 유연한 설계

 

✅  오버라이딩과 오버로딩 비교

구분 오버라이딩(Overriding) 오버로딩(Overloading)
개념 부모 클래스의 메서드를 자식 클래스에서 재정의 같은 이름의 메서드를 매개변수 타입/개수 다르게 정의
키워드 virtual, override 사용 없음 (단순히 같은 이름의 메서드 추가)
사용 예 Speak()를 Dog에서 재정의 Add(int a, int b)와 Add(double a, double b)

 

📌업캐스팅(Upcasting)

✅ 업캐스팅(Upcasting)이란?

🔹 자식 클래스의 객체를 부모 클래스 타입으로 변환하는 것
🔹 암시적(Implicit) 변환 가능 → 별도의 형 변환 연산자 없이 자동 변환됨
🔹 데이터 손실 없이 안전한 변환
🔹 부모 클래스에서 정의된 멤버(속성, 메서드)만 접근 가능
🔹 자식 클래스의 고유 멤버에는 접근할 수 없음

✅ 업캐스팅을 활용하는 이유

1️⃣ 다형성(Polymorphism) 지원

  • 부모 타입으로 여러 자식 객체를 관리할 수 있음
  • 유지보수성과 확장성이 뛰어남

2️⃣ 코드의 일관성 유지

  • 동일한 타입(부모)으로 처리하여 코드가 간결해짐

3️⃣ 컬렉션에서 활용 가능

  • List<Animal> 같은 자료구조에서 다양한 자식 객체를 저장할 때 유용
// 부모 클래스 (Animal)
class Animal
{
    public void Speak()
    {
        Console.WriteLine("동물이 소리를 내고 있습니다.");
    }
}

// 자식 클래스 (Dog) - Animal 클래스를 상속받음
class Dog : Animal
{
    public void Bark()
    {
        Console.WriteLine("멍멍!!");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Dog myDog = new Dog(); // 자식 클래스 객체 생성
        Animal myAnimal = myDog; // 업캐스팅 (Dog → Animal)

        myAnimal.Speak(); // ✅ 가능 (부모 클래스의 메서드는 호출 가능)

        // myAnimal.Bark(); // ❌ 오류 발생 (부모 타입으로 변환되어 자식 클래스의 메서드 사용 불가)
    }
}

 

📌다운캐스팅(Downcasting)

🔹 부모 타입의 객체를 다시 자식 타입으로 변환하는 것
🔹 명시적(Explicit) 형 변환이 필요 → (자식클래스) 부모객체 형태로 변환해야 함
🔹 업캐스팅된 객체를 다시 원래의 자식 타입으로 돌려놓는 과정
🔹 잘못된 다운캐스팅은 런타임 오류(InvalidCastException)를 발생시킬 수 있음

class Animal
{
    public void Speak()
    {
        Console.WriteLine("동물이 소리를 내고 있습니다.");
    }
}

class Dog : Animal
{
    public void Bark()
    {
        Console.WriteLine("멍멍!!");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Animal myAnimal = new Dog(); // 업캐스팅 (Dog → Animal)
        
        // 명시적 다운캐스팅 (부모 → 자식)
        Dog myDog = (Dog)myAnimal;  
        myDog.Bark(); // 정상 실행 (멍멍!! 출력)
    }
}

✅ 다운캐스팅이 필요한 경우

1️⃣ 자식 클래스의 고유 기능을 사용하고 싶을 때

  • 업캐스팅하면 부모 클래스의 기능만 사용할 수 있으므로, 다시 자식 클래스로 변환해야 할 경우 필요

2️⃣ 다형성을 활용할 때

  • 부모 타입 배열에 여러 자식 객체를 저장하고, 나중에 특정 타입으로 변환하여 추가 기능을 사용

✅ 안전한 다운캐스팅 방법

1️⃣ is 키워드 사용 (형 변환 가능 여부 확인)

if (myAnimal is Dog dog)
{
    dog.Bark(); // 안전하게 Bark() 호출
}
else
{
    Console.WriteLine("변환할 수 없는 타입입니다.");
}

2️⃣ as 키워드 사용 (형 변환 실패 시 null 반환)

Dog myDog = myAnimal as Dog;
if (myDog != null)
{
    myDog.Bark(); // 안전하게 Bark() 호출
}
else
{
    Console.WriteLine("변환할 수 없는 타입입니다.");
}

📌 base 키워드를 사용한 부모 클래스 호출하기

✅ base 키워드란?

  • base 키워드는 자식 클래스에서 부모 클래스의 멤버(메서드, 속성, 생성자 등)를 호출할 때 사용합니다.
  • 메서드를 오버라이딩했을 때, 부모 클래스의 원래 메서드도 실행하고 싶다면 base.메서드()를 호출하면 됩니다.
  • 부모 클래스의 생성자를 호출할 때도 base 키워드를 사용할 수 있습니다.

✅ base 키워드가 필요한 이유

  • 부모 클래스의 원래 기능을 유지하면서 추가적인 기능을 덧붙이고 싶을 때 사용합니다.
  • 오버라이딩한 메서드에서 부모 클래스의 원래 동작을 포함하려면 base.메서드()를 호출해야 합니다.
class Parent
{
    public virtual void ShowMessage()
    {
        Console.WriteLine("부모 클래스의 메세지");
    }
}

class Child : Parent
{
    public override void ShowMessage()
    {
        Console.WriteLine("자식 클래스의 메세지");
        base.ShowMessage(); // 부모 클래스의 ShowMessage() 호출
    }
}

class Program
{
    static void Main(string[] args)
    {
        Child child = new Child();
        child.ShowMessage();
    }
}

📌 상속에서 protected 접근 제한자와 생성자 실행 순서

class Player
{
    protected string Name; // 🔹 protected: 부모와 자식 클래스에서만 접근 가능

    public Player()
    {
        Name = "플레이어";
        Console.WriteLine("생성자입니다.");
    }

    public void Show()
    {
        Console.WriteLine(Name);
    }
}
class Wizard : Player//자식 클래스
{
    public Wizard()
    {
        Name = "마법사"; // 🔹 부모 클래스의 protected 멤버에 접근 가능
        Console.WriteLine("자식 생성자입니다.");
    }
}
class Program
{
    static void Main(string[] args)
    {
        Player p = new Player();
        p.Show();

        Wizard w = new Wizard();
        w.Show(); // 🔹 부모 생성자 -> 자식 생성자 순서로 실행됨
    }
}

1️⃣ Player p = new Player();

  • Player의 생성자 실행 → "생성자입니다." 출력.
  • Show() 실행 → "플레이어" 출력.

2️⃣ Wizard w = new Wizard();

  • 부모 클래스의 생성자 먼저 실행됨 → "생성자입니다." 출력.
  • Wizard의 생성자 실행 → "자식 생성자입니다." 출력.
  • Show() 실행 → "마법사" 출력

✅ 생성자 실행 순서 정리

✔ 자식 클래스의 생성자가 실행되기 전에 부모 클래스의 생성자가 먼저 실행됩니다.
✔ 이것은 상속 관계에서 부모의 초기화가 먼저 완료된 후, 자식이 추가적인 초기화를 진행하기 때문입니다.
✔ 이런 실행 순서는 base() 키워드를 통해 명시적으로 제어할 수도 있습니다.

728x90

'공부 > 부트캠프' 카테고리의 다른 글

[멋쟁이사자처럼부트캠프 Unity 게임개발 4기] 11일차: 델리게이트/이벤트/액션  (0) 2025.03.07
[멋쟁이사자처럼부트캠프 Unity게임개발 4기] 10일차 : 네임스페이스/인터페이스  (1) 2025.03.06
[멋쟁이사자처럼부트캠프 Unity게임개발 4기] 8일차: 예외처리/리스트/배열리스트/스택/큐  (1) 2025.03.04
[멋쟁이사자처럼부트캠프 Unity게임개발 4기] 7일차 : 클래스 + 캡슐화  (0) 2025.02.28
[멋쟁이사자처럼부트캠프 Unity게임개발 4기] 6일차 : 함수(메서드), 구조체, 클래스  (1) 2025.02.27
'공부/부트캠프' 카테고리의 다른 글
  • [멋쟁이사자처럼부트캠프 Unity 게임개발 4기] 11일차: 델리게이트/이벤트/액션
  • [멋쟁이사자처럼부트캠프 Unity게임개발 4기] 10일차 : 네임스페이스/인터페이스
  • [멋쟁이사자처럼부트캠프 Unity게임개발 4기] 8일차: 예외처리/리스트/배열리스트/스택/큐
  • [멋쟁이사자처럼부트캠프 Unity게임개발 4기] 7일차 : 클래스 + 캡슐화
knhoo
knhoo
  • knhoo
    &*
    knhoo
  • 전체
    오늘
    어제
    • 전체 (145)
      • Unity 개발일지 (20)
        • [Unity2D]졸업프로젝트 (17)
        • [Unity3D]VR프로젝트 (2)
      • 공부 (120)
        • 게임 수학 (1)
        • 부트캠프 (13)
        • C++ (39)
        • Unity & C# (8)
        • 데이터베이스 (2)
        • 컴퓨터비전 (0)
        • 컴퓨터구조 (0)
        • python (7)
        • BAEKJOON (39)
        • 개발 (2)
        • 자료구조 (9)
      • 일상 (2)
  • 블로그 메뉴

    • Github
    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

    • 📖README
  • 인기 글

  • 태그

    앱테크
    티스토리챌린지
    til
    Cpp
    Python
    백준
    패널파워
    캐시워크
    머니워크
    구간합
    멋쟁이사자처럼후기
    오블완
    백준 #python
    C++
    c#
    야핏무브
    자료구조
    unity
    비트버니
    unity2d
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
knhoo
[멋쟁이사자처럼부트캠프 Unity게임개발 4기] 9일차 : LINQ / 상속
상단으로

티스토리툴바