C# - C# 학습 정리 + Windows Form (3)
업데이트:
C# 프로그래밍
제네릭
기본
class Wanted<T>
{
public T value;
public Wanted(T value)
{
this.value = value;
}
}
class Program
{
static void Main(string[] args)
{
Wanted<string> wantedString = new Wanted<string>("문자");
Wanted<int> wantedInt = new Wanted<int>(3);
}
}
두 개 이상의 제네릭을 사용할 떄에는 쉼표로 구분합니다.
class Test<T, U>
{
}
where 키워드
where 키워드를 사용하면 제네릭 자료형을 제한할 수 있습니다.
class Test<T, U>
{
where T: class
where U: struct
}
위의 코드는 T는 클래스를 허용하고 U는 구조체만을 허용한다는 의미입니다.
class Test<T, U>
{
where T: IComparable
where U: IComparable, IDisposable
}
위의 코드는 IComparable이거나 이를 상속받은 것이어야 하는 의미입니다.
인덱서
리스트나 배열을 사용할 때, [] 형태로 인덱스를 많이 사용했습니다.
인덱서를 이용하면 클래스에서 []를 사용하여 배열처럼 사용할 수도 있습니다.
class Wanted
{
public int this[int i] { get { return i * i; } }
}
class Program
{
static void Main(string[] args)
{
Wanted square = new Wanted();
Console.WriteLine(square[10]);
Console.WriteLine(square[12]);
}
}
out 키워드
out 키워드를 사용하면 값을 여러 개 반환할 수 있습니다.
예를들어 TryParse() 메서드가 out 키워드를 사용하는 대표적인 메서드입니다.
public static bool TryParse(string s, out int result)
여기서 변경가능한 문자열을 넣으면 true를 반환하고 그게 아니라면 false를 반환합니다.
int output;
bool result = int.TryParse(Console.ReadLine(), out output);
if (result)
{
Console.WriteLine(output);
}
else
{
Console.WriteLine("실패");
}
실제로 메서드를 사용할 땐 다음과 같이 사용합니다.
static void NextPosition(int x, int vx, out int rx)
{
rx = x + vx;
}
static void main(string[] args)
{
int x = 0;
int vx = 1;
NextPosition(x, vx, out x);
Consol.WriteLine("다음좌표: " + x); // 1
}
구조체
구조체는 간단한 객체를 만들 때에 사용하는 형식입니다.
클래스와 거의 동일한 구문을 사용하지만 복사 형식이 다르고 제한이 많습니다.
상속이 불가능하고 인터페이스를 구현할 수도 없지만 클래스보다 안정성이 높습니다.
struct Point
{
public int x;
public int y;
}
static void Main(string[] args)
{
Point point;
point.x = 10;
point.y = 10;
}
구조체는 다음과 같이 생성자를 선언할 수 없습니다. 자동으로 정의되기 때문입니다.
그러나 매개변수가 있는 생성자는 생성할 수 있습니다. 다만 반드시 그 생성자 내에서 필드 변수 전부를 초기화하여야합니다.
또한 구조체의 필드 변수는 선언과 동시에 초기화를 할 수 없습니다.
struct Point
{
public int x;
public int y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
}
static void Main(string[] args)
{
Point point;
point.x = 10;
point.y = 10;
}
이처럼 구조체의 가장 중요한 의미는 안정성 이기 때문에 제약이 많습니다.
객체를 멤버 변수로 사용하더라도 null로 생성자에서 초기화를 시켜 주어야합니다.
또한 구조체는 클래스 객체와 달리 값복사가 일어납니다.
// 클래스 참조 복사
PointClass pointClassA = new PointClass(10,20);
PointClass pointClassB = pointClassA;
// 구조체 값 복사
PointStruct pointStructA = new PointStruct(10,20);
PointStruct pointStructB = pointStructA;
인터페이스
IComparable
Icomparable 인터페이스는 비교가 가능한 자료에 적용하며 모델 클래스에 많이 적용합니다.
class Product
{
public string Name { get; set; }
public int Price { get; set; }
public override string ToString()
{
return Name + " : " + Price;
}
}
static void Main(string[] args)
{
List<Product> list = new List<Product>()
{
new Product { Name = "고구마", Price = 1500 },
new Product { Name = "감자", Price = 2400 }
};
list.Sort();
foreach(var item in list)
{
Console.WriteLine(item);
}
}
위의 코드에서 정렬을 하게되면 기준이 없기 떄문에 예외가 발생합니다.
따라서 비교하는 기준을 정의해야하는데 여기서 IComparable 인터페이스를 상속하여 CompareTo 메서드를 구현합니다.
ToString()을 재정의하는 이유
모든 객체는 문자열 표현을 반환할 때 ToString()이 호출됩니다.
따라서 특정 클래스에서 이를 재정의하면 Console.WriteLine() 호출 시 재정의된 값으로 반환한다.
class Product: IComparable
{
public string Name { get; set; }
public int Price { get; set; }
public int CompareTo(object obj)
{
return this.Price.CompareTo((obj as Product).Price);
}
public override string ToString()
{
return Name + " : " + Price;
}
}
static void Main(string[] args)
{
List<Product> list = new List<Product>()
{
new Product { Name = "고구마", Price = 1500 },
new Product { Name = "감자", Price = 2400 }
};
list.Sort();
foreach(var item in list)
{
Console.WriteLine(item);
}
}
IDisposable
IDisposable 인터페이스는 using 블록을 사용할 때 자동으로 호출되는 규약입니다.
class Program
{
class Dummy: IDisposable
{
public void Dispose()
{
}
}
static void Main(string[] args)
{
using (Dummy dummy = new Dummy())
{
}
}
}
위의 코드에서 using 블록이 끝날 때 Dispose 메서드가 호출됩니다.
인터페이스 생성
인터페이스는 여러 곳에서 사용할 수 있으므로 보통 별도의 파일에 생성합니다.
namespace InterfaceBasic
{
interface IBasic
{
}
}
인터페이스 사용
인터페이스는 다른 언어와 마찬가지로 내부 구현을 할 수 없습니다.
namespace InterfaceBasic
{
interface IBasic
{
int TestMethod();
int TestProperty { get; set; }
}
}
class TestClass : IBasic
{
public int TestProperty { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public int TestMethod()
{
throw new NotImplementedException();
}
}
인터페이스 클래스가 부모이기 때문에 다형성을 구현할 수 있습니다. 그렇게 되면 다중 상속을 구현할 수 있게 됩니다.
인터페이스 다중 상속
대부분의 형대 언어는 다중 상속을 허용하지않지만 인터페이스는 다중 상속이 허용됩니다.
class TestClass : IBasic, IComparable
{
public int TestProperty { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public int CompareTo(object obj)
{
throw new NotImplementedException();
}
public int TestMethod()
{
throw new NotImplementedException();
}
}
주의 사항
여러 개의 인터페이스를 상속할 때, 메서드 이름이 겹칠 수 있는데 그 때에는 인터페이스이름.메서드이름()
형태로 구분해서 구현합니다.
윈도우 폼
메뉴
도구상자 - MenuStrip
상태 표시줄
도구상자 - StatusStrip
- 참고자료: C# 프로그래밍 - 한빛아카데미
댓글남기기