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# 프로그래밍 - 한빛아카데미

댓글남기기