... | ... | @@ -84,7 +84,7 @@ class Dog |
|
|
_name = name;
|
|
|
}
|
|
|
|
|
|
public void Bark() //이 메소드를 쓰려면 Dog.KingDog.Bark() 이런식으로 호출 가능하다.
|
|
|
public void Bark() //이 메서드를 쓰려면 Dog.KingDog.Bark() 이런식으로 호출 가능하다.
|
|
|
{
|
|
|
//멍멍
|
|
|
}
|
... | ... | @@ -94,7 +94,7 @@ class Dog |
|
|
Main 메서드의 인자로 사용되는 string 배열 사용 예제
|
|
|
|
|
|
```c#
|
|
|
public void Bark() //이 메소드를 쓰려면 Dog.KingDog.Bark() 이런식으로 호출 가능하다.
|
|
|
public void Bark() //이 메서드를 쓰려면 Dog.KingDog.Bark() 이런식으로 호출 가능하다.
|
|
|
{
|
|
|
Console.WriteLine("첫번째 인자로 멍멍이 입력되었습니다. 멍멍!");
|
|
|
}
|
... | ... | @@ -452,7 +452,7 @@ static void Main(string[] args) |
|
|
}
|
|
|
```
|
|
|
#### this
|
|
|
여러개의 생성자에서 private 메서드로 접근하여 처리하는 방법도 있다.
|
|
|
여러개의 생성자에서 지정해둔 하나의 private 메서드로 접근하여 처리하는 방법도 있다.
|
|
|
|
|
|
```c#
|
|
|
class Book
|
... | ... | @@ -600,7 +600,7 @@ GetHashCode는 해당 객체를 구별할 수 있는 key값을 반환하면 된 |
|
|
### 오버로드
|
|
|
이름만 같은 메서드가 매개변수의 수, 개별 매개변수 타입만 다르게 재정의하는 경우를 말한다.
|
|
|
|
|
|
#### 메소드 오버로드
|
|
|
#### 메서드 오버로드
|
|
|
```c#
|
|
|
class Animal
|
|
|
{
|
... | ... | @@ -704,21 +704,21 @@ class MoneyTest |
|
|
중첩 클래스(Nested class)는 클래스가 클래스를 포함한 것이다. 포함 관계에 있는 클래스들의 구조를 표현하고, 포함된 클래스가 포함한 클래스 외의 클래스에서 정의되는 것을 막을 수 있다. 중첩 클래스는 접근 제한자를 생략하면 private으로 설정되서 외부에서 인스턴스 생성이 불가능하다.
|
|
|
|
|
|
```c#
|
|
|
class Car
|
|
|
{
|
|
|
class Engine
|
|
|
{
|
|
|
class Car
|
|
|
{
|
|
|
class Engine
|
|
|
{
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
class Tire
|
|
|
{
|
|
|
class Tire
|
|
|
{
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
Engine turboEngine;
|
|
|
Tire[] tire;
|
|
|
}
|
|
|
Engine turboEngine;
|
|
|
Tire[] tire;
|
|
|
}
|
|
|
```
|
|
|
|
|
|
#### 추상 클래스
|
... | ... | @@ -748,12 +748,12 @@ class Circle : Shape |
|
|
```
|
|
|
|
|
|
#### 델리게이트
|
|
|
메서드 자체를 값으로 가지는 타입이다. 쉽게 말하면 메소드를 대신해서 호출하는 역할을 한다. 타입이기 때문에 다음의 특성을 가진다.
|
|
|
메서드 자체를 값으로 가지는 타입이다. 쉽게 말하면 메서드를 대신해서 호출하는 역할을 한다. 타입이기 때문에 다음의 특성을 가진다.
|
|
|
1. 메서드의 반환값으로 델리게이트를 사용할 수 있다.
|
|
|
2. 메서드의 인자로 델리게이트를 전달할 수 있다.
|
|
|
3. 클래스의 멤버로 델리게이트를 정의할 수 있다.
|
|
|
|
|
|
델리게이트를 쓰는 주 이유는 콜백을 구현하기 위해서이다. 일을 할 수 있는 판을 짜놓고 일을 하는데 필요한 정보는 런타임에 받아온다는게 콜백의 의미이다. 다양한 타입의 객체들을 정렬할 때, 객체 배열과 정렬 방법 함수를 델리게이트로 받아오면 다양한 상황에서의 처리를 하나의 코드로 할 수 있다.
|
|
|
델리게이트를 쓰는 주 이유는 콜백을 구현하기 위해서이다. 일을 할 수 있는 판을 짜놓고 일을 하다가 중간중간에 필요한 정보가 생기면 다른데에서 받아오는 것이 콜백의 의미이다. 다양한 타입의 객체들을 정렬할 때, 정렬 방법 함수만 바꿔가면서 델리게이트로 받아오면 다양한 상황에서의 처리를 하나의 코드로 할 수 있다.
|
|
|
|
|
|
델리게이트의 정의 형식은 다음과 같다.
|
|
|
>접근제한자 delegate 반환타입 이름(매개변수) 의 형식을 가진다.
|
... | ... | @@ -768,8 +768,9 @@ class DeleTest |
|
|
Console.WriteLine(dele(a, b)); //매개변수 a,b를 대상으로 dele가 가리키는 연산을 수행한다.(콜백)
|
|
|
}
|
|
|
|
|
|
public static int plus(int a, int b) { Console.Write("더하기!"); return a + b; } //정적/인스턴스 유형 메소드 모두 델리게이트가 가리킬 수 있다.
|
|
|
public static int minus(int a, int b) { Console.Write("빼기!"); return a - b; }
|
|
|
public static int plus(int a, int b) { Console.Write("더하기!"); return a + b; }
|
|
|
public static int minus(int a, int b) { Console.Write("빼기!"); return a - b; }
|
|
|
//정적/인스턴스 유형 메서드 모두 델리게이트가 가리킬 수 있다.
|
|
|
public int multiply(int a, int b) { return a * b; } //인스턴스 유형
|
|
|
|
|
|
public static void Main()
|
... | ... | @@ -778,7 +779,7 @@ class DeleTest |
|
|
|
|
|
CalcDelegate Plus = new CalcDelegate(plus);
|
|
|
CalcDelegate Minus = DeleTest.minus; //C# 2.0부터는 간단하게 사용가능.
|
|
|
CalcDelegate Multiply = new CalcDelegate(dt.multiply); //인스턴스 메소드
|
|
|
CalcDelegate Multiply = new CalcDelegate(dt.multiply); //인스턴스 메서드
|
|
|
CalcDelegate PlusAndMinus = Minus + Plus; //델리게이트 상대로 +,- 연산 가능.
|
|
|
|
|
|
Calc(3, 5, Plus);
|
... | ... | @@ -905,9 +906,7 @@ namespace ConsoleApplication1 |
|
|
```
|
|
|
|
|
|
#### 인터페이스
|
|
|
구현 없는 메서드 선언이 포함되어 있다. 다중 상속이 불가능하기 때문에 그것을 대체하기 위해서 쓴다. C# 컴파일러가 인터페이스의 메서드를 가상메서드로 간주하고 있기 때문에 인터페이스에서 virtual 예약어와 자식클래스에서 override 예약어를 쓰지 못하게 막는다.
|
|
|
* public을 명시해서 메서드 구현시 그 메서드는 클래스의 멤버로 호출 가능하다.
|
|
|
* public을 생략하면 인터페이스명.메서드명()으로 구현해야 하고 호출 또한 해당 인터페이스로 형변환 한 다음 호출해야한다.
|
|
|
구현 없는 메서드 선언이 포함되어 있다. C# 컴파일러가 인터페이스의 메서드를 가상메서드로 간주하고 있기 때문에 인터페이스에서 virtual 예약어와 자식클래스에서 override 예약어를 쓰지 못하게 막는다.
|
|
|
|
|
|
```c#
|
|
|
class Computer { }
|
... | ... | @@ -920,14 +919,7 @@ class NoteBook : Computer, IMonitor, IKeyboard |
|
|
{
|
|
|
public void display()
|
|
|
{
|
|
|
//override 예약어는 쓰지 않아도 되지만, public은 반드시 명시해야함. notebook.display() 가능
|
|
|
}
|
|
|
|
|
|
//또는
|
|
|
|
|
|
void IMonitor.display()
|
|
|
{
|
|
|
//이렇게 쓰면 호출 할 때에도 IMonitor mon = notebook as IMonitor; IMonitor.display() 식으로 형변환해서 호출해야한다.
|
|
|
//override 예약어는 쓰지 않아도 되지만, public은 반드시 명시해야함. notebook.display()와 같이 쓴다.
|
|
|
}
|
|
|
}
|
|
|
```
|
... | ... | @@ -975,16 +967,14 @@ class InterfaceTest |
|
|
{
|
|
|
if (obj is IDrawingObject) Console.WriteLine("인터페이스를 구현함.");
|
|
|
}
|
|
|
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
##### 인터페이스와 콜백
|
|
|
인터페이스로도 콜백을 구현 가능하다. 델리게이트와 차이는 다음과 같다.
|
|
|
인터페이스로도 콜백을 구현할 수 있다. 델리게이트와 차이는 다음과 같다.
|
|
|
* 델리게이트는 각 메서드 시그니쳐에 따라 다르게 정의해야 하지만, 인터페이스는 하나의 타입에서 여러 개의 메서드를 정의 가능하다.
|
|
|
* 델리게이트는 한 번에 여러 개의 메서드를 담을 수 있어서 한 번에 여러 개의 메서드 호출이 가능하다.
|
|
|
따라서 다중 호출에 대한 필요성이 없다면 인터페이스로 콜백을 구현하는 것이 일반적이다.
|
|
|
|
|
|
```c#
|
|
|
class AgeCompare : IComparer
|
... | ... | @@ -999,7 +989,7 @@ class AgeCompare : IComparer |
|
|
else return 1;
|
|
|
}
|
|
|
}
|
|
|
Array.Sort(PersonArray, New AgeCompare()); //나이를 기준으로 내림차순 정렬된다.
|
|
|
Array.Sort(PersonArray, New AgeCompare()); //PersonArray가 나이 내림차순 기준으로 정렬된다.
|
|
|
```
|
|
|
|
|
|
##### IEnumerable 인터페이스
|
... | ... | @@ -1033,13 +1023,13 @@ class Computer : IPower |
|
|
class Switch
|
|
|
{
|
|
|
public void PowerOn(IPower machine) //매개변수를 인터페이스로 받으면 클래스를 매개변수로 받는 것보다 느슨한 결합을 달성가능하다.
|
|
|
{
|
|
|
{ //클래스를 매개변수로 받으면 매개변수가 바뀌었을 때 Computer를 Monitor로 바꿔도 Switch에 대한 코드를 수정해야한다.(강한 결합)
|
|
|
machine.TurnOn();
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
#### 구조체
|
|
|
사용자 정의 형식지만 값 형식을 가진다. 클래스와 차이는 다음과 같다.
|
|
|
사용자 정의 형식이지만 값 형식을 가진다. 클래스와 차이는 다음과 같다.
|
|
|
1. 인스턴스 생성을 new로 해도 되고, 안 해도 된다. (new로 하면 구조체 내 모든 속성값 0으로 할당.)
|
|
|
2. 기본 생성자는 명시적으로 정의할 수 없다.
|
|
|
3. 매개변수를 갖는 생성자를 정의해도 기본 생성자가 C# 컴파일러에 의해 자동으로 포함된다.
|
... | ... | @@ -1091,9 +1081,10 @@ class Program |
|
|
* 값에 의한 호출 : 메서드의 인자 전달 시 변수의 스택 값이 복사되어 전달되는 것을 말한다.
|
|
|
* 참조에 의한 호출 : 해당 변수의 스택 값을 담고 있는 주소 자체가 전달되는 것을 말한다.
|
|
|
|
|
|
그래서 참조에 의한 호출이 얕은 복사와 비슷해 보이지만 차이점은 얕은 복사는 스택 내에 새로운 공간을 할당하고 그 공간이 같은 주소를 가리키고 있다는 것이고, 참조에 의한 호출은 동일한 공간을 참조한다는 점이 다르다. 그림을 보면 차이점이 확실히 드러난다.
|
|
|
그래서 참조에 의한 호출과 얕은 복사가 비슷해 보이지만 차이점이 있다. 얕은 복사는 스택 내에 새로운 공간을 할당하고 그 공간도 같은 주소를 가리키게 된다. 하지만 참조에 의한 호출은 스택 내에 새로운 공간을 만들지 않고 동일한 공간을 참조한다는 점이 다르다. 그림을 보면 차이점이 확실히 드러난다.
|
|
|
|
|
|
다음은 얕은 복사와 참조에 의한 호출을 비교한 그림이다.
|
|
|
|
|
|
얕은 복사에 대한 그림이다.
|
|
|

|
|
|
|
... | ... | @@ -1106,7 +1097,114 @@ class Program |
|
|
1. out으로 지정된 인자에 넘길 변수는 초기화하지 않아도 된다. 초기화돼 있어도 out 인자를 받는 메서드에서는 그 값을 사용할 수 없다.
|
|
|
2. out으로 지정된 인자를 받는 메서드는 반드시 변수에 값을 넣어서 반환해야 한다.
|
|
|
|
|
|
```c#
|
|
|
class OutTest
|
|
|
{
|
|
|
static bool Divide(int n1, int n2, out int result)
|
|
|
{
|
|
|
if (n2 == 0)
|
|
|
{
|
|
|
result = 0; //out으로 선언한 result에 대한 초기화가 이루어지지 않으면 에러발생.
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
result = n1 / n2;
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
public static void Main()
|
|
|
{
|
|
|
int divideResult = 5;
|
|
|
|
|
|
if(OutTest.Divide(10, 0, out divideResult) == true)
|
|
|
{
|
|
|
Console.WriteLine(divideResult);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
Console.WriteLine("0으로나눌수없어!");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
결국 ref 예약어는 기존 변수를 메서드 내에서 수정하려 할 때 사용하고, out 예약어는 메서드 내에서 수정된 값을 반환하려 할 때 사용한다.
|
|
|
|
|
|
#### 열거형
|
|
|
#### 열거형
|
|
|
값 형식으로 byte, sbyte, short, ushort, int, uint, long, ulong만을 상속받아 정의할 수 있는 제한된 사용자 정의 타입이다. 타입을 지정하지 않으면 int 형으로 지정된다. 코드의 가독성을 높이거나, 오타로 인한 오류를 줄여줄 수 있다.
|
|
|
|
|
|
사용 예
|
|
|
```c#
|
|
|
class EnumTest
|
|
|
{
|
|
|
[Flags]
|
|
|
enum Status : int
|
|
|
{
|
|
|
Menu = 1, GameStart = 2, GameOver = 4, Ranking = 8, Option = 16
|
|
|
//OR연산을 했을 시 값이 다른 값에 먹히지 않으려면 2의 배수로 증가시켜야 함.
|
|
|
//미 정의시 0부터 시작해서 1씩 증가.
|
|
|
}
|
|
|
|
|
|
public static void Main()
|
|
|
{
|
|
|
Status status = Status.GameOver;
|
|
|
Console.WriteLine(status); //출력값은 GameOver.
|
|
|
Console.WriteLine((int)status); //출력값은 2.
|
|
|
|
|
|
Status status2 = Status.GameOver | Status.GameStart | Status.Ranking | Status.Option;
|
|
|
|
|
|
if (status2.HasFlag(Status.GameOver)) //포함여부 확인가능.
|
|
|
{
|
|
|
Console.WriteLine("GameOver를 포함하고 있습니다.");
|
|
|
}
|
|
|
|
|
|
Console.WriteLine(status2); //OR연산을 하고 출력하면 합계 값이 나온다. [Flags] 선언시 요소 이름으로 출력
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### 멤버 유형 확장
|
|
|
|
|
|
<br />
|
|
|
|
|
|
#### 읽기 전용 필드
|
|
|
readonly 예약어를 사용하면 클래스 내부에서 읽기만 가능하고 초기화도 1번만 가능하다. 내부적으로 불변 상태를 보장하기 위하여 쓴다.
|
|
|
|
|
|
```c#
|
|
|
public class ReadonlyEx
|
|
|
{
|
|
|
readonly int num = 10; //변수 선언에서 초기화 가능.
|
|
|
|
|
|
public ReadonlyEx()
|
|
|
{
|
|
|
this.num = 3; //생성자에서 초기화 가능. 둘 다 했을 시 생성자에서 덮어쓰기 함.
|
|
|
}
|
|
|
|
|
|
public void test()
|
|
|
{
|
|
|
//this.num = 10; 그 외의 장소에서는 초기화하면 에러.
|
|
|
}
|
|
|
|
|
|
public static void Main()
|
|
|
{
|
|
|
ReadonlyEx ex = new ReadonlyEx();
|
|
|
|
|
|
Console.WriteLine(ex.num);
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
#### 상수
|
|
|
리터럴에 식별자를 붙인것이다. 리터럴의 재사용과 수정을 용이하게 해준다.
|
|
|
> 접근제한자 const 상수타입 식별자 = 값; 으로 사용한다.
|
|
|
|
|
|
다음은 상수의 몇 가지 특징이다.
|
|
|
1. 상수는 static 예약어가 허용되지 않는다. (의미상으론 static에 해당한다.)
|
|
|
2. 기본 자료형에 대해서만 상수 정의가 가능하다.
|
|
|
3. 반드시 상수 정의와 함께 값을 대입해야 한다. 생성자에서 접근 불가.
|
|
|
4. 컴파일할 때 소스코드에 값이 치환되는 방식으로 구현된다.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|