호출자 정보
class CallerInfo
{
public static void Main()
{
LogMessage("test");
}
//호출자 정보는 '호출하는 측의 정보'를 메서드의 인자로 전달하는 것이다.
//호출자 정보 특성이 명시된 매개변수는 선택적 매개변수 형식이여야 한다.
//컴파일 시점에 값이 치환되어 빌드된다.
static void LogMessage(string text,
[CallerMemberName] string memberName = "",
[CallerFilePath] string filePath = "",
[CallerLineNumber] int lineNumber = 0)
{
Console.WriteLine("텍스트 : " + text); //"test" 출력
Console.WriteLine("이 메서드를 호출하는 메서드 이름" + memberName); //Main 출력
Console.WriteLine("호출 파일 경로" + filePath); //파일 경로 출력
Console.WriteLine("메서드가 호출된 라인 번호" + lineNumber); //10 출력
}
}
비동기 호출
async/await 예약어
비동기 호출에 await 예약어가 함께 쓰이면 C# 컴파일러는 이를 인지하고 그 이후의 코드를 묶어서 비동기 호출이 끝난 다음에 실행되도록 코드를 변경해서 컴파일한다. async 예약어가 있으면 컴파일러는 await 예약어를 예약어로 인식한다. async 예약어가 없으면 그냥 식별자로 인식한다.
class AsyncAwaitTest
{
//async 예약어가 없이 await를 사용할 수 없다.
private static async void AwaitRead()
{
using (FileStream fs = new FileStream("test.log", FileMode.Open))
{
byte[] buffer = new byte[fs.Length];
Console.WriteLine("실행 전의 스레드 id : " + Thread.CurrentThread.ManagedThreadId);
await fs.ReadAsync(buffer, 0, buffer.Length);
Console.WriteLine("실행 후의 스레드 id : " + Thread.CurrentThread.ManagedThreadId);
//ReadAsync 이하의 처리는 스레드 풀 스레드가 담당하기 때문에 스레드 id가 다르게 나온다.
//이하의 라인은 ReadAsync 비동기 호출이 완료된 후 호출
string txt = Encoding.UTF8.GetString(buffer);
Console.WriteLine(txt);
}
}
public static void Main()
{
AwaitRead();
Console.ReadLine();
}
}
class BCLAsyncTest //WebClient 비동기 호출 async/await 예제
{
public static void Main()
{
AwaitDownloadString();
Console.ReadLine();
}
private static async void AwaitDownloadString()
{
WebClient wc = new WebClient();
wc.Encoding = Encoding.UTF8;
//DownloadStringAsync보다 더 간편하게 이용 가능.
string text = await wc.DownloadStringTaskAsync("http://www.naver.com");
Console.WriteLine(text);
}
}
class BCLAsyncTest2 //TCP 서버 비동기 통신 예제
{
public static void Main()
{
TcpListener listener = new TcpListener(IPAddress.Any, 11200);
listener.Start();
while (true)
{
//연결 요청을 받아들인다.
var client = listener.AcceptTcpClient();
ProcessTcpClient(client);
}
}
//NetworkStream 클래스의 ReadAsync와 WriteAsync를 이용하면 간단하게 비동기 통신 구현 가능
private static async void ProcessTcpClient(TcpClient client)
{
NetworkStream ns = client.GetStream();
byte[] buffer = new byte[1024];
int received = await ns.ReadAsync(buffer, 0, buffer.Length);
string txt = Encoding.UTF8.GetString(buffer, 0 ,received);
byte[] sendBuffer = Encoding.UTF8.GetBytes("Hello : " + txt);
await ns.WriteAsync(sendBuffer, 0, sendBuffer.Length);
ns.Close();
}
}
Task, Task 타입
Async 메서드의 반환값은 모두 Task 또는 Task 유형이다. Task 타입은 반환값이 없는 경우 사용되고, Task 타입은 TResult 형식 매개변수로 지정된 반환값이 있는 경우로 구분된다.
class TaskType
{
public static void Main()
{
//스레드 풀에서
ThreadPool.QueueUserWorkItem((obj) => { Console.WriteLine("process workitem"); }, null);
Task task1 = new Task(() => { Console.WriteLine("process taskitem"); });
task1.Start();
Task task2 = new Task((obj) => { Console.WriteLine("process taskitem(obj)"); }, null);
task2.Start();
task1.Wait(); //task1의 작업이 끝날 때까지 현재 스레드를 대기한다.
task2.Wait();
//task 객체를 생성할 필요 없이 바로 작업 시작 가능.
Task.Factory.StartNew(() => { Console.WriteLine("process taskitem StartNew"); });
//Task<TResult> 타입은 값을 반환할 수 있다.
Task<int> task3 = new Task<int>(() =>
{
Random rand = new Random((int)DateTime.Now.Ticks);
return rand.Next();
}
);
task3.Start();
task3.Wait();
Console.WriteLine("무작위 숫자 값 : " + task3.Result);
//StartNew<TResult> 도 반환.
Task<int> taskReturn = Task.Factory.StartNew<int>(() => 255);
taskReturn.Wait();
Console.WriteLine(taskReturn.Result);
}
}