C# - C# 학습 정리 + Windows Form (5)
업데이트:
C# 프로그래밍
델리게이터
델리게이터란
C#에서는 델리게이터와 람다라는 개념으로 메서드를 변수로 사용할 수 있습니다.
델리게이터는 일종의 클래스를 선언하는 것과 같습니다.
delegate void TestDelegate(); // 델리게이터 자료형 선언
TestDelegate testDelegate = <메서드 이름, 무명 델리게이터, 람다> // 델리게이터 변수 생성
한 가지 예로 Sort() 메서드를 보겠습니다.
class Program
{
class Product
{
public string Name { get; set; }
public int Price { get; set; }
}
static void Main(string[] args)
{
List<Product> products = new List<Product>()
{
new Product() { Name = "감자", Price = 500},
new Product() { Name = "사과", Price = 700},
new Product() { Name = "고구마", Price = 400}
};
// 정렬
foreach (var item in products)
{
Console.WriteLine(item.Name + " : " + item.Price);
}
}
}
위의 메서드에서 정렬하는 코드를 작성하면 됩니다.
이전에는 IComparable 인터페이스를 구현했는데 이번에는 Sort() 메서드의 두 번째 형태를 봅시다.
void List<Product> Sort(Comparison<Product> comparison)
Comparison<>는 델리게이터입니다.
delegate System.Comparison
class Program
{
class Product
{
public string Name { get; set; }
public int Price { get; set; }
}
static void Main(string[] args)
{
List<Product> products = new List<Product>()
{
new Product() { Name = "감자", Price = 500},
new Product() { Name = "사과", Price = 700},
new Product() { Name = "고구마", Price = 400}
};
products.Sort(SortWithPrice);
// 정렬
foreach (var item in products)
{
Console.WriteLine(item.Name + " : " + item.Price);
}
}
static int SortWithPrice(Product a, Product b)
{
return a.Price.CompareTo(b.Price);
}
}
실제로 Comparison 델리게이터를 마이크로소프트 MSDN 문서에서 확인해보면 다음과 같습니다.
public delegate int Comparison<in T>(
T x,
T y
)
따라서 int 자료형을 반환하고 제네릭을 사용한 매개변수 두 개를 넣어주면 됩니다.
하지만 이렇게하면 정렬한 종류만큼의 메서드를 만들어주어야해서 불편합니다.
이러한 불편함 때문에 사용하는 것이 무명 델리게이터 입니다.
products.Sort(delegate (Product a, Product b)
{
return a.Price.CompareTo(b.Price);
});
무명 델리게이터를 이용하여 이벤트도 연결할 수 있습니다.
button.Click += delegate(object sender, EventArgs e)
{
}
람다
델리게이터를 사용할 때 조금 더 편하게 사용할 수 있는 것이 람다입니다.
(<매개변수>, <매개변수>) => {
/* 코드 */
return /* 반환 */
}
(a, b) => /* 반환 */
위와 같이 사용하는 것이 대부분 입니다.
아까 전의 정렬 델리게이터 코드를 람다식으로 바꿔보도록 하겠습니다.
products.Sort((a, b) =>
{
return a.Price.CompareTo(b.Price);
});
// 또는
products.Sort((a, b) => a.Price.CompareTo(b.Price));
델리게이터 선언
무명 델리게이터를 사용하지 않고 처음에 설명했던 것 처럼 이름이 있는 델리게이터를 선언할 수 있습니다.
델리게이터는 클래스 외부에도 선언할 수 있습니다.
public delegate void TestDelegateA();
class Program
{
public delegate void TestDelegateB();
static void Main(string[] args)
{
TestDelegateA delegateA;
TestDelegateB delegateB;
}
}
초기화를 하려면 다음과 같이 초기화할 수 있습니다.
class Program
{
public delegate void TestDelegate();
static void Main(string[] args)
{
TestDelegate delegateA = TestMethod;
TestDelegate delegateB = delegate() { };
TestDelegate delegateC = () => { };
// 호출
delegateA();
delegateB();
delegateC();
}
static void TestMethod()
{
}
}
콜백 메서드
델리게이터를 활용하는 가장 대표적인 형태는 콜백 메서드 입니다.
기본적으로 다음과 같은 형태입니다.
public delegate void CustomDelegate(); // 델리게이터 선언
public void Method(CustomDelegate customDelegate)
{
customDelegate(); // 델리게이터 호출
}
class Student
{
public string Name { get; set; }
public double Score { get; set; }
public Student(string name, double score)
{
this.Name = name;
this.Score = score;
}
public override string ToString()
{
return this.Name + " : " + this.Score;
}
}
class Students
{
private List<Student> listOfStudent = new List<Student>();
public delegate void PrintProcess(Student list);
public void Add(Student student)
{
listOfStudent.Add(student);
}
//
public void Print()
{
Print((stu) =>
{
Console.WriteLine(stu);
});
}
public void Print(PrintProcess process)
{
foreach (var item in listOfStudent)
{
process(item); // ** 델리게이터 호출
}
}
}
class Program
{
public delegate void TestDelegate(); // 델리게이터 선언
static void Main(string[] args)
{
Students students = new Students();
students.Add(new Student("이재환", 4.2));
students.Add(new Student("이재환12", 4.5));
students.Print(); // 단순 출력
students.Print((stu) => // 별도의 출력
{
});
}
}
델리게이터 연산
델리게이터 연산도 가능합니다.
기본적으로 +, -만 가능합니다. 여러개의 델리게이트가 있으면 해당 델리게이터 변수가 갖는 메서드를 모두 호출합니다.
class Program
{
public delegate void SendString(string message);
static void Main(string[] args)
{
SendString sayHello, sayGoocbye, multiDelegate;
sayHello = Hello;
sayGoocbye = GoodBye;
multiDelegate = sayHello + sayGoocbye;
multiDelegate("이재환");
Console.WriteLine();
multiDelegate -= sayGoocbye;
multiDelegate("이재환11");
}
public static void Hello(string message)
{
Console.WriteLine("안녕하세요 " + message);
}
public static void GoodBye(string message)
{
Console.WriteLine("안녕히가세요" + message);
}
}
델리게이터 이벤트
델리게이터는 event 키워드와 함께 많이 사용합니다.
public delegate void MyEventHandler(string message);
class Publisher
{
public event MyEventHandler Active;
public void DoActive(int number)
{
if (number % 10 == 0)
Active("Active!" + number);
else
Console.WriteLine(number);
}
}
class Subscriber
{
static public void MyHandler(string message)
{
Console.WriteLine(message);
}
static void Main(string[] args)
{
Publisher publisher = new Publisher();
publisher.Active += new MyEventHandler(MyHandler);
for (int i = 1; i < 50; i++)
publisher.DoActive(i);
}
}
클로저
클로저 변수란 메서드가 끝나도 사라지지 않고 남는 현상에서의 변수를 의미합니다.
델리게이터나 람다가 생긴 이후, 이 안에서 해당 변수가 사용되면 생성자나 메서드가 끝나도 계속 살아있게 됩니다.
따라서 현재는 메서드가 끝나는 순간에 소멸자가 호출되는 것이 아니라 변수가 더 이상 사용되지 않을 것이 확실할 때 소멸자가 호출됩니다.
쓰레드
쓰레드 생성
쓰레드를 생성할 때에는 메서드, 무명 델리게이터, 람다를 사용합니다.
Thread threadA = new Thread(TestMethod);
Thread threadA = new Thread(delegate()
{
});
Thread threadA = new Thread(() =>
{
});
쓰레드 실행
실행은 위의 쓰레드를 생성했으면 { } 안에 실행할 동작을 삽입하고 다음 함수를 호출합니다.
threadA.start();
윈도우 폼
델리게이터와 람다 활용
button.Click += delegate (object sender, EventArgs args) {
};
button.Click += (sender, args) =>
{
};
대화상자
대화상자는 파일을 지정하는 팝업창을 여는 등의 역할을 합니다.
private void button1_Click(object sender, EventArgs e)
{
saveFileDialog1.ShowDialog();
MessageBox.Show(saveFileDialog1.FileName);
}
원하는 파일만 선택가능하게 할 수도 있습니다.
private void button1_Click(object sender, EventArgs e)
{
saveFileDialog1.Filter = "텍스트 파일 (*.txt)|*.txt"; // 글자|형식|글자|형식...
saveFileDialog1.ShowDialog();
File.WriteAllText(saveFileDialog1.FileName, "hello"); // 파일 저장
}
이외에도 다양한 대화상자가 있습니다.
- 색상 대화상자: ColorDialog
- 폰트 대화상자: FontDialog
- 파일 열기 대화상자: OpenFileDialog
동적 생성
대화상자는 동적으로 생성하는게 더 편할 수 있습니다.
디자인을 거치지않고 코드에서 바로 생성합니다.
private void button1_Click(object sender, EventArgs e)
{
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.Filter = "텍스트 파일 (*.txt)|*.txt"; // 글자|형식|글자|형식...
saveFileDialog.ShowDialog();
File.WriteAllText(saveFileDialog1.FileName, "hello");
}
- 참고자료: C# 프로그래밍 - 한빛아카데미
댓글남기기