... | @@ -1196,7 +1196,7 @@ public class ReadonlyEx |
... | @@ -1196,7 +1196,7 @@ public class ReadonlyEx |
|
|
|
|
|
#### 상수
|
|
#### 상수
|
|
리터럴에 식별자를 붙인것이다. 리터럴의 재사용과 수정을 용이하게 해준다.
|
|
리터럴에 식별자를 붙인것이다. 리터럴의 재사용과 수정을 용이하게 해준다.
|
|
> 접근제한자 const 상수타입 식별자 = 값; 으로 사용한다.
|
|
> [접근제한자] const [상수타입] [식별자] = 값; 으로 사용한다.
|
|
|
|
|
|
다음은 상수의 몇 가지 특징이다.
|
|
다음은 상수의 몇 가지 특징이다.
|
|
1. 상수는 static 예약어가 허용되지 않는다. (의미상으론 static에 해당한다.)
|
|
1. 상수는 static 예약어가 허용되지 않는다. (의미상으론 static에 해당한다.)
|
... | @@ -1204,7 +1204,176 @@ public class ReadonlyEx |
... | @@ -1204,7 +1204,176 @@ public class ReadonlyEx |
|
3. 반드시 상수 정의와 함께 값을 대입해야 한다. 생성자에서 접근 불가.
|
|
3. 반드시 상수 정의와 함께 값을 대입해야 한다. 생성자에서 접근 불가.
|
|
4. 컴파일할 때 소스코드에 값이 치환되는 방식으로 구현된다.
|
|
4. 컴파일할 때 소스코드에 값이 치환되는 방식으로 구현된다.
|
|
|
|
|
|
|
|
#### 이벤트
|
|
|
|
정형화 된 콜백 패턴을 구현할 때 event 예약어를 쓰면 코드를 줄일 수 있다. 이벤트의 특징은 다음과 같다.
|
|
|
|
1. 클래스에서 이벤트를 제공한다.
|
|
|
|
2. 외부에서 자유롭게 해당 이벤트를 구독하거나 해지하는 것이 가능하다.
|
|
|
|
3. 외부에서 구독/해지는 가능하지만 이벤트 발생은 오직 내부에서만 가능하다.
|
|
|
|
4. 이벤트의 첫 번째 인자는 이벤트를 발생시킨 타입의 인스턴스다.
|
|
|
|
5. 이벤트의 두 번째 인자는 해당 이벤트에 속한 의미 있는 값이 제공된다.
|
|
|
|
|
|
|
|
이벤트는 GUI를 제공하는 응용 프로그램에서 일반적으로 사용된다. 윈도우에 포함된 버튼이 있고 버튼을 눌렀을 때 해야하는 작업이 있다면, 버튼 클래스 제작자는 Click 이라는 이벤트를 구현해두고, 버튼을 이용하는 개발자는 Click 이벤트를 구독하는 메서드 내에서 작업 수행 코드를 작성하면 된다.
|
|
|
|
|
|
|
|
>**이벤트 선언 방법**
|
|
|
|
> [접근제한자] delegate [리턴타입] [델리게이트명] [파라미터];
|
|
|
|
> [접근제한자] event [델리게이트명] [이벤트명];
|
|
|
|
|
|
|
|
```c#
|
|
|
|
namespace ConsoleApplication1
|
|
|
|
{
|
|
|
|
//class CallbackArg { } //유연성을 위해 상속 구조를 만들어서 실행 메서드 내에서 다시 형변환 하는 방식.
|
|
|
|
|
|
|
|
class PrimeCallbackArgs : EventArgs //CallbackArg대신 닷넷에서 제공하는 EventArgs 상속.
|
|
|
|
{
|
|
|
|
public int prime;
|
|
|
|
|
|
|
|
public PrimeCallbackArgs(int prime)
|
|
|
|
{
|
|
|
|
this.prime = prime;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class PrimeGenerator //발행자 클래스.
|
|
|
|
{
|
|
|
|
//public delegate void PrimeDelegate(object sender, EventArgs arg);
|
|
|
|
//public event PrimeDelegate PrimeGenerated; //델리게이트를 정의하고 그 델리게이트를 위한 이벤트 정의가능.
|
|
|
|
|
|
|
|
public event EventHandler PrimeGenerated;
|
|
|
|
//닷넷에서 제공하는 EventHandler를 사용한 경우.
|
|
|
|
|
|
|
|
//콜백 메서드 추가/삭제하는 메서드. 이벤트를 사용하면 더 간결하게 쓸 수 있다.
|
|
|
|
//public void AddDelegate(PrimeDelegate callback)
|
|
|
|
//{
|
|
|
|
// callbacks = Delegate.Combine(callbacks, callback) as PrimeDelegate;
|
|
|
|
//}
|
|
|
|
|
|
|
|
//public void RemoveDelegate(PrimeDelegate callback)
|
|
|
|
//{
|
|
|
|
// callbacks = Delegate.Remove(callbacks, callback) as PrimeDelegate;
|
|
|
|
//}
|
|
|
|
|
|
|
|
public void Run(int limit)
|
|
|
|
{
|
|
|
|
for (int i = 2; i <= limit; i++)
|
|
|
|
{
|
|
|
|
if (IsPrime(i) == true && PrimeGenerated != null)
|
|
|
|
//이벤트 발생 조건과(여기에선 소수여부) 이벤트를 구독하는 구독자가 있는지 검사.
|
|
|
|
{
|
|
|
|
PrimeGenerated(this, new PrimeCallbackArgs(i));
|
|
|
|
//발행자 내부에서 이벤트 발생.
|
|
|
|
//System.EventHandler는 두 개의 매개변수를 요구.
|
|
|
|
//이벤트의 첫 번째 인자는 이벤트를 발생시킨 타입의 인스턴스.
|
|
|
|
//이벤트의 두 번째 인자는 해당 이벤트에 속한 의미 있는 값.(여기에선 소수값)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private bool IsPrime(int candidate)
|
|
|
|
{
|
|
|
|
if ((candidate & 1) == 0)
|
|
|
|
{
|
|
|
|
return candidate == 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 3; (i * i) <= candidate; i += 2)
|
|
|
|
{
|
|
|
|
if ((candidate % i) == 0) return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return candidate != 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class Program //구독자 클래스
|
|
|
|
{
|
|
|
|
static void PrintPrime(object sender, EventArgs arg)
|
|
|
|
{
|
|
|
|
Console.Write((arg as PrimeCallbackArgs).prime + ", ");
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sum;
|
|
|
|
|
|
|
|
static void SumPrime(object sender, EventArgs arg)
|
|
|
|
{
|
|
|
|
sum += (arg as PrimeCallbackArgs).prime;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Main()
|
|
|
|
{
|
|
|
|
PrimeGenerator gen = new PrimeGenerator(); //이벤트 발행자 객체 행성. 이벤트 구독자는 현재 객체.
|
|
|
|
//gen.PrimeGenerated(this, new PrimeCallbackArgs(i)); //이벤트 선언 클래스 외에서 호출 시 에러.
|
|
|
|
|
|
|
|
//PrimeGenerator.PrimeDelegate callprint = PrintPrime;
|
|
|
|
//gen.AddDelegate(callprint);
|
|
|
|
|
|
|
|
//PrimeGenerator.PrimeDelegate callsum = SumPrime;
|
|
|
|
//gen.AddDelegate(callsum);
|
|
|
|
//이벤트를 쓰면 아래와 같이 코드를 줄일 수 있다.
|
|
|
|
|
|
|
|
//외부에서 구독/해지 가능
|
|
|
|
gen.PrimeGenerated += PrintPrime; //PrintPrime 메서드의 이벤트 등록
|
|
|
|
gen.PrimeGenerated += SumPrime; //SumPrime 메서드의 이벤트 등록
|
|
|
|
|
|
|
|
gen.Run(10);
|
|
|
|
Console.WriteLine();
|
|
|
|
Console.WriteLine(sum);
|
|
|
|
|
|
|
|
//gen.RemoveDelegate(callsum);
|
|
|
|
gen.PrimeGenerated -= SumPrime; //SumPrime 메서드의 이벤트 해지
|
|
|
|
gen.Run(15);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
#### 인덱서
|
|
|
|
|
|
|
|
클래스 내의 배열로 된 멤버 변수에 바로 접근할 수 있게 해주는 것이다. 인덱서를 만들면 대괄호 연산자 사용을 인스턴스에 할 수 있다. 클래스가 직관적으로 비열처럼 다뤄질 수 있을 때 사용하기 쉽도록 제공되는 구문이다.
|
|
|
|
사용 예시는 다음과 같다.
|
|
|
|
```c#
|
|
|
|
class IndexerEx
|
|
|
|
{
|
|
|
|
private const int MAX = 10;
|
|
|
|
private string name;
|
|
|
|
|
|
|
|
private int[] arr = new int[MAX];
|
|
|
|
|
|
|
|
public int this[int index] //int형으로 인덱스 지정
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
if (index < 0 || index >= MAX)
|
|
|
|
{
|
|
|
|
throw new IndexOutOfRangeException();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return arr[index]; //범위에 벗어나지 않으면 arr[] 배열에서 get
|
|
|
|
}
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
if (index < 0 || index >= MAX)
|
|
|
|
{
|
|
|
|
throw new IndexOutOfRangeException();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
arr[index] = value; //범위에 벗어나지 않으면 arr[] 배열에 set
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class Program
|
|
|
|
{
|
|
|
|
public static void Main()
|
|
|
|
{
|
|
|
|
IndexerEx ex = new IndexerEx();
|
|
|
|
|
|
|
|
ex[1] = 1024; //인덱서 set 사용
|
|
|
|
|
|
|
|
int i = ex[1]; //인덱서 get 사용
|
|
|
|
}
|
|
|
|
}
|
|
|
|
``` |