예제 코드 1)
interface IMyInterface // 이름 앞에 I를 붙인다.
{
void Method1();
int Method2(string str);
}
class MyClass : IMyInterface // 상속과 사용법이 비슷하다.
{
public void Method1() // 인터페이스에 존재하는 멤버들을 모두 구현해야 한다.
{
// 구현
}
public int Method2(string str)
{
// 구현
return 0;
}
}
예제 코드 2)
public class Player : IMovable
{
public void Move(int x, int y)
{
// 플레이어의 이동 구현
}
}
public class Enemy : IMovable
{
public void Move(int x, int y)
{
// 적의 이동 구현
}
}
IMovable movableObject1 = new Player();
IMovable movableObject2 = new Enemy();
movableObject1.Move(5, 0); // 플레이어 이동
movableObject2.Move(1, 9); // 적 이동
예제 코드 3)
// 아이템을 사용할 수 있는 인터페이스
public interface IUsable
{
void Use();
}
// 아이템 클래스
public class Item : IUsable
{
public string Name { get; set; }
public void Use()
{
Console.WriteLine("아이템 {0}을 사용했습니다.", Name);
}
}
// 플레이어 클래스
public class Player
{
public void UseItem(IUsable item)
{
item.Use();
}
}
// 게임 실행
static void Main()
{
Player player = new Player();
Item item = new Item { Name = "Health Potion" };
player.UseItem(item);
}
예제 코드 4)
// 인터페이스 1
public interface IItemPickable
{
void PickUp();
}
// 인터페이스 2
public interface IDroppable
{
void Drop();
}
// 아이템 클래스
public class Item : IItemPickable, IDroppable
{
public string Name { get; set; }
public void PickUp()
{
Console.WriteLine("아이템 {0}을 주웠습니다.", Name);
}
public void Drop()
{
Console.WriteLine("아이템 {0}을 버렸습니다.", Name);
}
}
// 플레이어 클래스
public class Player
{
public void InteractWithItem(IItemPickable item)
{
item.PickUp();
}
public void DropItem(IDroppable item)
{
item.Drop();
}
}
// 게임 실행
static void Main()
{
Player player = new Player();
Item item = new Item { Name = "Sword" };
// 아이템 주울 수 있음
player.InteractWithItem(item);
// 아이템 버릴 수 있음
player.DropItem(item);
}
인터페이스의 특징과 장단점
인터페이스는 추상적인 동작만 정의하고, 구현을 갖지 않는다.
다중 상속이 가능하며, 여러 클래스가 동일한 인터페이스를 구현할 수 있다.
클래스들 간의 결합도를 낮추고, 유연한 상호작용을 가능하게 한다.
코드의 재사용성과 확장성을 향상시킨다.
단점으로는 인터페이스를 구현하는 클래스가 모든 동작을 구현해야 한다는 의무를 가지기 때문에 작업량이 증가할 수 있다.
추상 클래스의 특징과 장단점
추상 클래스는 일부 동작의 구현을 가지며, 추상 메서드를 포함할 수 있다.
단일 상속만 가능하며, 다른 클래스와 함께 상속 계층 구조를 형성할 수 있다.
공통된 동작을 추상화하여 코드의 중복을 방지하고, 확장성을 제공한다.
구현된 동작을 가지고 있기 때문에, 하위 클래스에서 재정의하지 않아도 될 경우 유용하다.
단점으로는 다중 상속이 불가능하고, 상속을 통해 밀접하게 결합된 클래스들을 형성하므로 유연성이 제한될 수 있다.
예제 코드 1)
enum MyEnum
{
Value1,
Value2,
Value3
}
MyEnum myEnum = MyEnum.Value1;
예제 코드 2)
enum MyEnum
{
Value1 = 10,
Value2, // Value2 = 11이 된다.
Value3 = 20
}
에제 코드 3)
int intValue = (int)MyEnum.Value1; // 열거형 값을 정수로 변환
MyEnum enumValue = (MyEnum)intValue; // 정수를 열거형으로 변환
예제 코드 4)
switch(enumValue)
{
case MyEnum.Value1:
// Value1에 대한 처리
break;
case MyEnum.Value2:
// Value2에 대한 처리
break;
case MyEnum.Value3:
// Value3에 대한 처리
break;
default:
// 기본 처리
break;
}
예제 코드 5)
// 월 열거형
public enum Month
{
January = 1,
February,
March,
April,
May,
June,
July,
August,
September,
October,
November,
December
}
// 처리하는 함수
static void ProcessMonth(int month)
{
if (month >= (int)Month.January && month <= (int)Month.December)
{
Month selectedMonth = (Month)month;
Console.WriteLine("선택한 월은 {0}입니다.", selectedMonth);
// 월에 따른 처리 로직 추가
}
else
{
Console.WriteLine("올바른 월을 입력해주세요.");
}
}
// 실행 예제
static void Main()
{
int userInput = 7; // 사용자 입력 예시
ProcessMonth(userInput);
}
예제 코드 6)
// 게임 상태
enum GameState
{
MainMenu,
Playing,
Paused,
GameOver
}
// 방향
enum Direction
{
Up,
Down,
Left,
Right
}
// 아이템 등급
enum ItemRarity
{
Common,
Uncommon,
Rare,
Epic
}
예외는 프로그램 실행 중 예기치 못한 상황을 의미하며, 보통 오류로 이어진다. 예외 처리를 통해 오류를 방지하고 프로그램을 안정적으로 유지한다.
try-catch
블록을 사용하여 수행한다.
예제 코드 1)
try
{
// 예외가 발생할 수 있는 코드
}
catch (ExceptionType1 ex)
{
// ExceptionType1에 해당하는 예외 처리
}
catch (ExceptionType2 ex)
{
// ExceptionType2에 해당하는 예외 처리
}
finally
{
// 예외 발생 여부와 상관없이 항상 실행되는 코드
}
catch
블록이 먼저 실행된다.catch
블록catch
블록을 사용하여 다양한 예외 타입을 처리할 수 있다. 각각의 예외 타입에 코드를 작성할 수 있다.try-catch
블록 뒤에 작성되며, 생략할 수 있다.예제 코드 2)
try
{
int result = 10 / 0; // ArithmeticException 발생
Console.WriteLine("결과: " + result);
}
catch (DivideByZeroException ex)
{
Console.WriteLine("0으로 나눌 수 없습니다.");
}
catch (Exception ex)
{
Console.WriteLine("예외가 발생했습니다: " + ex.Message);
}
finally
{
Console.WriteLine("finally 블록이 실행되었습니다.");
}
예제 코드 3)
public class NegativeNumberException : Exception
{
public NegativeNumberException(string message) : base(message)
{
}
}
try
{
int number = -10;
if (number < 0)
{
throw new NegativeNumberException("음수는 처리할 수 없습니다.");
}
}
catch (NegativeNumberException ex)
{
Console.WriteLine(ex.Message);
}
catch (Exception ex)
{
Console.WriteLine("예외가 발생했습니다: " + ex.Message);
}
예제 코드 4)
// 플레이어 이동
try
{
// 플레이어 이동 코드
if (IsPlayerCollidingWithWall())
{
throw new CollisionException("플레이어가 벽에 충돌했습니다!");
}
}
catch (CollisionException ex)
{
// 충돌 예외 처리
Debug.Log(ex.Message);
// 예외에 대한 추가 처리
}
// 리소스 로딩
try
{
// 리소스 로딩 코드
LoadResource("image.png");
}
catch (ResourceNotFoundException ex)
{
// 리소스가 없는 경우 예외 처리
Debug.Log(ex.Message);
// 예외에 대한 추가 처리
}
catch (ResourceLoadException ex)
{
// 리소스 로딩 중 오류가 발생한 경우 예외 처리
Debug.Log(ex.Message);
// 예외에 대한 추가 처리
}
// 게임 상태 전이
try
{
// 상태 전이 코드
if (currentGameState != GameState.Playing)
{
throw new InvalidStateException("게임이 실행 중이 아닙니다!");
}
// 게임 상태 전이 실행
}
catch (InvalidStateException ex)
{
// 상태 예외 처리
Debug.Log(ex.Message);
// 예외에 대한 추가 처리
}
struct MyStruct
{
public int Value;
}
MyStruct struct1 = new MyStruct();
struct1.Value = 10;
MyStruct struct2 = struct1; // struct2는 struct1의 값 복사
struct2.Value = 20;
Console.WriteLine(struct1.Value); // 출력 결과: 10
class MyClass
{
public int Value;
}
MyClass obj1 = new MyClass();
obj1.Value = 10;
MyClass obj2 = obj1; // obj2는 obj1과 동일한 객체를 참조
obj2.Value = 20;
Console.WriteLine(obj1.Value); // 출력 결과: 20
예제 코드 1)
using System;
class Program
{
static void Main()
{
// 값형
int x = 10;
int y = x;
y = 20;
Console.WriteLine("x: " + x); // 출력 결과: 10
Console.WriteLine("y: " + y); // 출력 결과: 20
// 참조형
int[] arr1 = new int[] { 1, 2, 3 };
int[] arr2 = arr1;
arr2[0] = 4;
Console.WriteLine("arr1[0]: " + arr1[0]); // 출력 결과: 4
Console.WriteLine("arr2[0]: " + arr2[0]); // 출력 결과: 4
// 박싱과 언박싱
int num1 = 10;
object obj = num1; // 박싱
int num2 = (int)obj; // 언박싱
Console.WriteLine("num1: " + num1); // 출력 결과: 10
Console.WriteLine("num2: " + num2); // 출력 결과: 10
}
}
예제 코드 2)
List<object> myList = new List<object>();
// 박싱: 값 형식을 참조 형식으로 변환하여 리스트에 추가
int intValue = 10;
myList.Add(intValue); // int를 object로 박싱하여 추가
float floatValue = 3.14f;
myList.Add(floatValue); // float를 object로 박싱하여 추가
// 언박싱: 참조 형식을 값 형식으로 변환하여 사용
int value1 = (int)myList[0]; // object를 int로 언박싱
float value2 = (float)myList[1]; // object를 float로 언박싱
예제 코드 1)
delegate int Calculate(int x, int y);
static int Add(int x, int y)
{
return x + y;
}
class Program
{
static void Main()
{
// 메서드 등록
Calculate calc = Add;
// 델리게이트 사용
int result = calc(3, 5);
Console.WriteLine("결과: " + result);
}
}
예제 코드 2)
delegate void MyDelegate(string message);
static void Method1(string message)
{
Console.WriteLine("Method1: " + message);
}
static void Method2(string message)
{
Console.WriteLine("Method2: " + message);
}
class Program
{
static void Main()
{
// 델리게이트 인스턴스 생성 및 메서드 등록
MyDelegate myDelegate = Method1;
myDelegate += Method2;
// 델리게이트 호출
myDelegate("Hello!");
Console.ReadKey();
}
}
예제 코드 3)
// 델리게이트 선언
public delegate void EnemyAttackHandler(float damage);
// 적 클래스
public class Enemy
{
// 공격 이벤트
public event EnemyAttackHandler OnAttack;
// 적의 공격 메서드
public void Attack(float damage)
{
// 이벤트 호출
OnAttack?.Invoke(damage);
// null 조건부 연산자
// null 참조가 아닌 경우에만 멤버에 접근하거나 메서드를 호출
}
}
// 플레이어 클래스
public class Player
{
// 플레이어가 받은 데미지 처리 메서드
public void HandleDamage(float damage)
{
// 플레이어의 체력 감소 등의 처리 로직
Console.WriteLine("플레이어가 {0}의 데미지를 입었습니다.", damage);
}
}
// 게임 실행
static void Main()
{
// 적 객체 생성
Enemy enemy = new Enemy();
// 플레이어 객체 생성
Player player = new Player();
// 플레이어의 데미지 처리 메서드를 적의 공격 이벤트에 추가
enemy.OnAttack += player.HandleDamage;
// 적의 공격
enemy.Attack(10.0f);
}
예제 코드 1)
(parameter_list) => expression
Calculate calc = (x, y) =>
{
return x + y;
};
Calculate calc = (x, y) => x + y;
예제 코드 2)
using System;
// 델리게이트 선언
delegate void MyDelegate(string message);
class Program
{
static void Main()
{
// 델리게이트 인스턴스 생성 및 람다식 할당
MyDelegate myDelegate = (message) =>
{
Console.WriteLine("람다식을 통해 전달된 메시지: " + message);
};
// 델리게이트 호출
myDelegate("안녕하세요!");
Console.ReadKey();
}
}
예제 코드 3)
// 델리게이트 선언
public delegate void GameEvent();
// 이벤트 매니저 클래스
public class EventManager
{
// 게임 시작 이벤트
public event GameEvent OnGameStart;
// 게임 종료 이벤트
public event GameEvent OnGameEnd;
// 게임 실행
public void RunGame()
{
// 게임 시작 이벤트 호출
OnGameStart?.Invoke();
// 게임 실행 로직
// 게임 종료 이벤트 호출
OnGameEnd?.Invoke();
}
}
// 게임 메시지 클래스
public class GameMessage
{
public void ShowMessage(string message)
{
Console.WriteLine(message);
}
}
// 게임 실행
static void Main()
{
// 이벤트 매니저 객체 생성
EventManager eventManager = new EventManager();
// 게임 메시지 객체 생성
GameMessage gameMessage = new GameMessage();
// 게임 시작 이벤트에 람다 식으로 메시지 출력 동작 등록
eventManager.OnGameStart += () => gameMessage.ShowMessage("게임이 시작됩니다.");
// 게임 종료 이벤트에 람다 식으로 메시지 출력 동작 등록
eventManager.OnGameEnd += () => gameMessage.ShowMessage("게임이 종료됩니다.");
// 게임 실행
eventManager.RunGame();
}
Func
는 값을 반환하는 메서드를 나타내는 델리게이트. 마지막 제네릭 형식 매개변수는 반환 타입을 나타낸다. 예를 들어, Func<int, string>
은 int를 입력받아 string
을 반환하는 메서드를 나타낸다.Action
은 값을 반환하지 않는 메서드를 나타내는 델리게이트. 매개변수를 받아들이지만, 반환 타입이 없다. 예를 들어, Action<int, string>
은 int
와 string
을 입력받고, 아무런 값을 반환하지 않는 메서드를 나타낸다.예제 코드 1)
// Func를 사용하여 두 개의 정수를 더하는 메서드
int Add(int x, int y)
{
return x + y;
}
// Func를 이용한 메서드 호출
Func<int, int, int> addFunc = Add;
int result = addFunc(3, 5);
Console.WriteLine("결과: " + result);
예제 코드 2)
// Action을 사용하여 문자열을 출력하는 메서드
void PrintMessage(string message)
{
Console.WriteLine(message);
}
// Action을 이용한 메서드 호출
Action<string> printAction = PrintMessage;
printAction("Hello, World!");
예제 코드 3)
// 게임 캐릭터 클래스
class GameCharacter
{
private Action<float> healthChangedCallback;
private float health;
public float Health
{
get { return health; }
set
{
health = value;
healthChangedCallback?.Invoke(health);
}
}
public void SetHealthChangedCallback(Action<float> callback)
{
healthChangedCallback = callback;
}
}
// 게임 캐릭터 생성 및 상태 변경 감지
GameCharacter character = new GameCharacter();
character.SetHealthChangedCallback(health =>
{
if (health <= 0)
{
Console.WriteLine("캐릭터 사망!");
}
});
// 캐릭터의 체력 변경
character.Health = 0;
var result = from 변수 in 데이터소스
[where 조건식]
[orderby 정렬식 [, 정렬식...]]
[select 식];
var
키워드는 결과 값의 자료형을 자동으로 추론합니다.from
절에서는 데이터 소스를 지정합니다.where
절은 선택적으로 사용하며, 조건식을 지정하여 데이터를 필터링합니다.orderby
절은 선택적으로 사용하며, 정렬 방식을 지정합니다.select
절은 선택적으로 사용하며, 조회할 데이터를 지정합니다.예제 코드 1)
// 데이터 소스 정의 (컬렉션)
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
// 쿼리 작성 (선언적인 구문)
var evenNumbers = from num in numbers
where num % 2 == 0
select num;
// 쿼리 실행 및 결과 처리
foreach (var num in evenNumbers)
{
Console.WriteLine(num);
}
솔직히 하루만에 이해하기에는 개념적인 부분들이 너무 많고 정보의 양도 방대하다. . . 하지만 중간중간 나오는 정보들을 보니 튜터님의 해설 코드에 있었던 것들이 있었고, 그때는 기능의 구현 정도만 이해하고 넘어갔지만 오늘 개념들을 공부할 수 있어서 좋았다. 두고두고 펼쳐보며 자주 보아야 이해할 수 있을 듯 하다. 과제를 수행하면서 기능들을 계속해서 사용해 봐야지 개념이나 정의를 이해할 수 있었음을 이미 경험했기에 조급함은 가지지 않기로 했다. (과제가 산더미이기 때문 . . . 😶😶)