Generic (일반화)
object obj = 3;
object obj2 = "hello world";
int num = (int)obj;
string str = (string)obj2;
// var와 차이점은?
// var는 컴파일러가 컴파일타임제 데이터형을 지정해 준다.
// object는 자료형의 최상위 부모이다.
// generic class
class MyList<T>
{
T[] arr = new T[10];
public T GetItem(int i)
{
return arr[i];
}
}
// Main
MyList<int> myIntList = MyList<int>();
MyList<float> myIntList = MyList<float>();
함수 일반화도 가능
static void Test<T>(int input)
{
}
Test<int>(3);
Test<float>(3);
generic의 조건도 지정이 가능하다
class MyList<T> where T : new() // 기본생성자를 무조건 포함해달라
class MyList<T> where T : class // class로 생성되어야 한다.
class MyList<T> where T : struct // struct로 생성되어야 한다.
class MyList<T> where T : Monster // Monster 클래스의 자녀여야 한다.
Interface
// 추상클래스
class Monster
{
// 자녀 클래스에서 Shout를 무조건 만들게 할 순 없나?
public virtual void Shout() {}
}
// Monster자체를 abstract로 만든다.
abstract class Monster
{
public abstract void Shout(); // 함수의 내용이 있으면 안됨
}
class Orc : Monster
{
public override void Shout()
{
}
}
abstract class Flyable
{
public abstract void Fly();
}
class FlyableOrc : Orc, Flyable // Error : C#은 다중상속 지원 안함
interface IFlyable
{
void Fly();
}
class FlyableOrc : Orc, IFlyable
{
public void Fly() {} // Okay
}
Property
class Knight
{
private int hp;
public int GetHp() { return hp; }
public void SetHp(int hp) { this.hp = hp; }
}
좀 더 편하게 할순 없나?
class Knight
{
private int hp;
public int Hp
{
get { return hp; }
/*private (지정가능)*/set { this.hp = value; }
}
}
// 사용은
Knight knight = new Knight();
knight.Hp = 100;
int _hp = knight.Hp;
더 펀하게는??
class Knight
{
public int Hp
{
get; set;
} = 100; // 초기화도 가능
}
Delegate
delegate int OnClicked();
static void ButtonPressed(OnClicked Func)
{
Func();
}
static int TestDelegate()
{
Console.WriteLine("Hello");
}
static int TestDelegate2()
{
Console.WriteLine("Hello2");
}
static void Main(string[] args)
{
ButtonPressed(TestDelegate);
// 이런것도 가능
OnClicked clicked = new OnClicked(TestDelegate);
clicked += TestDelegate2;
ButtonPressed(clicked); // 두 개의 Delegate가 모두 호출된다.
}
Event
class InputManager
{
public delegate void OnInputKey();
public event OnInputKey InputKey;
public void Update()
{
// 키 입력을 확인
if(Console.KeyAvailable == false)
return;
ConsoleKeyInfo info = Console.ReadKey();
if(info.Key == ConsoleKey.A)
{
// 모두에게 알려주자
InputKey();
}
}
}
// ...
// Main
static void OnInputTest()
{
}
static void Main(string[] args)
{
InputManager inputManager = new InputManager();
// 이벤트 연결
inputManager.InputKey +=OnInputTest;
while(true)
{
inputManager.Update();
}
}
Action
static void Main(string[] args)
{
// 1. 기존 메서드 지정
Action<string> _action1 = Print;
_action1("action1");
// 2. 무명 메서드 지정
Action<string, string> _action2 = delegate(string msg, string error)
{
Console.WriteLine(msg, error);
};
_action2("action2", "inform");
// 3. 람다식 사용
Action<int, int> _action3 = (x, y) => {
Console.WriteLine("{0} + {1} = {2}", x, y, x + y);
};
}
public static void Print(string msg)
{
Console.WriteLine(msg);
}
Lambda
enum ItemType
{
Weapon,
Armor,
Amulet,
Ring
}
enum Rarity
{
Normal,
Uncommon,
Rare
}
class Item
{
public ItemType ItemType;
public Rarity Rarity;
}
class Program
{
static List<Item> _items = new List<Item>();
// 모든 조건에 따라 Find함수를 만들어야하나?
// Rare도 만들고 이후에 조건이 추가되면 또 만들고???
static Item FindWeapon()
{
foreach(Item item in _items)
{
if(item.ItemType == ItemType.Weapon)
return item
}
return null;
}
static void Main(string[] args)
{
_items.Add(new Item() { ItemType = ItemType.Weapon, Rarity = Rarity.Normal });
_items.Add(new Item() { ItemType = ItemType.Armor, Rarity = Rarity.Uncommon });
_items.Add(new Item() { ItemType = ItemType.Amulet, Rarity = Rarity.Rare });
}
}
class Program
{
static List<Item> _items = new List<Item>();
// delegate이용해보기
delegate bool ItemSelector(Item item);
// 여전히 단점은 아래와 같은 판별 함수를 만들어 줘야한다는 점.
static bool IsWeapon(Item item)
{
return item.ItemType == ItemTypeWeapon;
}
static Item FindItem(ItemSelector selector)
{
foreach(Item item in _items)
{
if(selector(item))
return item
}
return null;
}
static void Main(string[] args)
{
_items.Add(new Item() { ItemType = ItemType.Weapon, Rarity = Rarity.Normal });
_items.Add(new Item() { ItemType = ItemType.Armor, Rarity = Rarity.Uncommon });
_items.Add(new Item() { ItemType = ItemType.Amulet, Rarity = Rarity.Rare });
Item item = FindItem(IsWeapon);
}
}
class Program
{
static List<Item> _items = new List<Item>();
delegate bool ItemSelector(Item item);
static Item FindItem(ItemSelector selector)
{
foreach(Item item in _items)
{
if(selector(item))
return item
}
return null;
}
static void Main(string[] args)
{
_items.Add(new Item() { ItemType = ItemType.Weapon, Rarity = Rarity.Normal });
_items.Add(new Item() { ItemType = ItemType.Armor, Rarity = Rarity.Uncommon });
_items.Add(new Item() { ItemType = ItemType.Amulet, Rarity = Rarity.Rare });
// 아래와 같이 무명함수로 처리가능(람다식과는 다름)
Item item = FindItem(delegate (Item item) {
return item.ItemType == ItemTypeWeapon;
}));
}
}
class Program
{
static List<Item> _items = new List<Item>();
delegate bool ItemSelector(Item item);
static Item FindItem(ItemSelector selector)
{
foreach(Item item in _items)
{
if(selector(item))
return item
}
return null;
}
static void Main(string[] args)
{
_items.Add(new Item() { ItemType = ItemType.Weapon, Rarity = Rarity.Normal });
_items.Add(new Item() { ItemType = ItemType.Armor, Rarity = Rarity.Uncommon });
_items.Add(new Item() { ItemType = ItemType.Amulet, Rarity = Rarity.Rare });
// 람다식
Item item = FindItem((Item item) => {
return item.ItemType == ItemTypeWeapon;
}));
}
}
추가
class Program
{
static List<Item> _items = new List<Item>();
// delegate Retrun MyFunc<T, Retrun>(T item);
// 이걸 C#에서 자체 지원함 Func로 사용하면 된다.
// 참고로 void리턴은 Action을 사용하면 됨.
// static Item FindItem(MyFunc<Item, bool> selector)
static Item FindItem(Func<Item, bool> selector)
{
foreach(Item item in _items)
{
if(selector(item))
return item
}
return null;
}
static void Main(string[] args)
{
_items.Add(new Item() { ItemType = ItemType.Weapon, Rarity = Rarity.Normal });
_items.Add(new Item() { ItemType = ItemType.Armor, Rarity = Rarity.Uncommon });
_items.Add(new Item() { ItemType = ItemType.Amulet, Rarity = Rarity.Rare });
// MyFunc<Item, bool> selector = (Item item) => { return item.ItemType == ItemTypeWeapon; };
Func<Item, bool> selector = (Item item) => { return item.ItemType == ItemTypeWeapon; };
Item item = FindItem(selector);
}
}
Exception
try
{
// * 0으로 나누는 경우
int a = 5;
int b = 0;
int result = a / b;
// * 잘못된 메모리 참조
// * 오버플로
}
catch(DivideByZeroException e)
{
// * 0으로 나누는 경우
}
catch(Exception e)
{
// exception 내부에 예외상황에 대한 설명이 나와있음
}
finally
{
// catch이후 과정을 넣음
}
Reflection
X-Ray를 찍는효과
class Monster
{
public int hp;
protected int attack;
private float speed;
void Attack() {}
}
// Main
Monster monster = new Monster();
Type type = monster.GetType(); // GetType은 C#의 object아래 있음
var fields = type.GetFields(BindingFlags.Public);
// 런타임에 Monster 내부의 변수/함수를 확인가능
Nullable