1. CLR의 타입 시스템
- CLR : 공통 언어 런타임, 즉 모든 C# 코드의 실행 환경
- 타입 안정성 : 잘못된 타입 사용방지
- 모든 타입은 'System.Object'에서 파생됨.
2. 값 타입
- struct, enum 두가지 형식(값 형식은 sealed)
- int, long, double, char, bool등,
- 스택에 할당되며, 값 자체를 저장한다.
- 변수간의 복사는 값 자체의 복사이다.
int // System.Int32
long // System.Int64
double // System.Double
int a = 0; // System.Int32 a = new System.Int32();
- 변수간 복사는 값자체의 복사이므로, GC 관여없이 효율적이다.
int a = 10;
int b = a;
b = 20;
Console.WriteLine(a); // 10
3. 참조타입
- class, interface, array, delegate등,
- 힙에 저장되며, 변수는 각 객체의 참조(주소)를 저장한다.
- 복사는 참조만 전달하게 된다.
class Person { public string Name; }
Person p1 = new Person { Name = "Alice" };
Person p2 = p1;
p2.Name = "Bob";
Console.WriteLine(p1.Name); // "Bob"
깊은 복사 예시
class Car {
public string Model { get; set; }
}
static void Main() {
Car car1 = new Car { Model = "Toyota" };
Car car2 = car1; // car1과 같은 객체를 참조 (얕은 복사)
car2.Model = "Honda"; // car2를 수정하면 car1에도 영향이 있음
Console.WriteLine(car1.Model); // 출력: Honda
Console.WriteLine(car2.Model); // 출력: Honda
Console.WriteLine(object.ReferenceEquals(car1, car2)); // 출력: True (같은 객체 참조)
// 깊은 복사 예시 (새로운 객체 생성, 문자열은 값 복사됨)
Car car3 = new Car { Model = car1.Model };
car3.Model = "Ford"; // car3만 변경, car1은 영향 없음
Console.WriteLine(car1.Model); // 출력: Honda
Console.WriteLine(car3.Model); // 출력: Ford
}
4. 박싱
- 값 타입을 참조 타입(object)로 변환시킨다.
- CLR 동작 : 값이 스택에서 힙으로 이동하며, 새 객체를 생성한다.
int num = 10;
object obj = num; // 박싱
5. 언박싱
- 참조타입에서 값 타입으로 변환.
- CLR 동작 : 타입이 맞지 않으면 invaildCastException이 발생하게 된다.
* 참고로 박싱과 언박싱은 성은 오버헤드가 발생하므로 주의해야함(메모리 할당 및 GC 부담)
int num 2 = (int)obj; // 언박싱
InvalidCastException은 잘못된 형 변환(캐스트)을 시도할 때 발생하는 예외입니다.
즉, 호환되지 않는 형식 간의 변환을 수행하려 할 때 발생합니다.
InvalidCastException이 발생하는 경우
부모-자식 관계가 아닌 타입 변환 시
object obj = "Hello";
int num = (int)obj; // ❌ InvalidCastException 발생!
- obj는 문자열이지만, 이를 int로 변환하려고 하면 예외 발생!
클래스 간 잘못된 캐스트
class Animal { }
class Dog : Animal { }
class Cat : Animal { }
static void Main()
{
Animal a = new Dog();
Cat c = (Cat)a; // ❌ InvalidCastException 발생!
}
- a는 Dog 타입인데, Cat으로 변환하려 하면 예외 발생.
3️⃣ 인터페이스 구현이 안 된 객체를 인터페이스로 캐스팅
interface ICar { }
class Car { }
static void Main()
{
Car myCar = new Car();
ICar carInterface = (ICar)myCar; // ❌ InvalidCastException 발생!
}
- Car 클래스가 ICar를 구현하지 않았기 때문에 변환 불가.
해결 방법
- as 키워드 사용
- object obj = "Hello"; string str = obj as string; //
- 올바른 변환 (실패하면 null 반환) if (str != null) { Console.WriteLine(str); }
- is 키워드로 타입 확인 후 변환
- object obj = "Hello"; if (obj is string) { string str = (string)obj; Console.WriteLine(str); }
- TryCast(C#에서는 직접 구현 필요)
- C#에는 TryCast가 없지만, is와 as를 활용하여 예외를 방지할 수 있음.
🔥 결론
InvalidCastException은 잘못된 형 변환을 시도할 때 발생하는 예외이며,
as 키워드 또는 is 키워드로 방지할 수 있음.
System.Object
- 모든 타입의 기본 클래스
- 주요 메서드
- ToString() : 문자열 표현
- Equals() : 동등성 비교
- GetHashCode() : 해시코드
- GetType() : 런타임 타입정보
int i = 42;
Console.WriteLine(i.GetType()); // System.Int32
C++ 구조체와 C#의 구조체의 다른점
- C++
- 스택 힙 가능.(스택기본)
- 상속 가능
- 접근지정자 기본 public
- 생성자 가능
- 소멸자 가능
- 값타입 기본(힙도 가능)
- 얕은 복사
- C#
- 스택 기본 / 힙 직접 할당 불가.
- 상속 불가능(인터페이스만 가능)
- 기본 private
- 생성자 매개변수 있는 생성자는 가능. (없으면 불가능)
- 소멸자 불가능
- 값타입 (힙 직접 할당 불가)
- 깊은 복사(Deep Copy)
using System;
class Q
{
public string Question { get; set; } // 문제
public string Answer { get; set; } // 정답
public int Difficulty { get; set; } // 난이도 (1~3)
}
class Program
{
static void Main()
{
// 퀴즈 데이터 구성 //클래스 배열
Q[] quizzes = new Q[]
{
new Q { Question = "C#에서 정수를 저장하는 데이터 타입은?", Answer = "int", Difficulty = 1 },
new Q { Question = "2 + 3은 얼마인가?", Answer = "5", Difficulty = 1 },
new Q { Question = "C#에서 문자열을 나타내는 타입은?", Answer = "string", Difficulty = 2 }
};
int totalScore = 0; // 총 점수
int totalQuestions = quizzes.Length; // 퀴즈 개수
// foreach로 quizzes 배열을 순차적으로 반복
foreach (var quiz in quizzes)
{
Console.WriteLine(quiz.Question); // quiz.Question은 현재 퀴즈의 질문을 출력
string userAnswer = Console.ReadLine(); // 사용자로부터 답을 입력받음
// 정답 확인
if (userAnswer.Equals(quiz.Answer, StringComparison.OrdinalIgnoreCase))
{
int score = quiz.Difficulty * 10; // 난이도 * 10 점 부여
totalScore += score;
Console.WriteLine($"정답입니다! 점수: {score}점");
}
else
{
Console.WriteLine("틀렸습니다!");
}
}
// 총점과 평균 점수 출력
double averageScore = (double)totalScore / totalQuestions;
Console.WriteLine($"\\n총 점수: {totalScore}점");
Console.WriteLine($"평균 점수: {averageScore:F2}점");
}
}
- foreach (var quiz in quizzes)는 C#에서 배열 또는 컬렉션을 순차적으로 반복하는 방법입니다.
- 이 코드는 quizzes라는 배열이나 리스트에 저장된 각 퀴즈 객체를 하나씩
- quiz 변수에 할당하면서 반복적으로 실행됩니다.
- 즉, 배열의 각 요소에 대해 자동으로 하나씩 접근할 수 있게 해주는 구문입니다.
구체적인 설명
- quizzes: 배열 또는 컬렉션(예: 리스트, 배열 등). 이 코드에서는 Q 객체들이 들어있는 배열입니다.
- quiz: 배열의 각 요소를 하나씩 참조하는 변수입니다. 여기서는 각 퀴즈를 quiz라는 이름으로 다룰 수 있습니다.
- var: var는 암시적 타입 추론을 사용하여, quiz의 타입을 자동으로 결정합니다.
- 여기서는 Q 클래스 객체를 의미합니다.
- 즉, quizzes 배열 안의 각 항목은 Q 타입의 객체이므로 var를 사용하여 quiz를 Q 타입으로 처리합니다.
'Game DevTip > C#' 카테고리의 다른 글
4. C# 인터페이스 및 추상클래스 ,다형성 (0) | 2025.04.21 |
---|---|
3. C# 클래스 (1) | 2025.04.21 |
2. C# 배열, 함수, 델리게이트 (0) | 2025.04.21 |
댓글