Microsoft MVP성태의 닷넷 이야기
이벤트 부분을 읽고 있는데 이해가 안되서 질문합니다.. [링크 복사], [링크+제목 복사]
조회: 12688
글쓴 사람
김철환
홈페이지
첨부 파일
 

p.252 관련한 질문인데요 event에 대해 풀어서 구현 설명을 하고 있는 것 같은데 코드 이해가 안되서 질문드립니다. 난수 생성은 그렇다 치더라도 이해가 안되서 질문 드립니다

모르는 부분은 코드 옆에 주석으로 질문 했습니다

namespace Cons_Application
{
    class CallbackArg { } //이 부분을 왜 비워놓았는데 PrimeCallbackArg에서 상속을 받는 건가요?? 아무런 기능도 안하는 건데 말이죠??

    class PrimeCallbackArg : CallbackArg
    {
        public int Prime;
        public PrimeCallbackArg(int Prime)
        {
            this.Prime = Prime;
        }
    }






    class PrimeGenerator
    {
        public delegate void PrimeDelegate(object sender, CallbackArg arg);// 여기서 CallbackArg 클래스 안에는 내용이 아무것도 없는데 왜 인자로 전달한 것일까요??
        PrimeDelegate callbacks;
        public void AddDelegate(PrimeDelegate callback)
        {
            callbacks = Delegate.Combine(callbacks, callback) as PrimeDelegate;
        }
        public void RemoveDelegate(PrimeDelegate callback)
        {
            callbacks = Delegate.Remove(callbacks, callback) as PrimeDelegate;
        }

        // 여기부분에서 콜백 메서드를 호출한다고 했는데 어느 부분이 호출 한다는 건가요 if 조건문 을 만족하면 callbacks()실행을 하는 부분이 호출하는 것인가요??
        public void Run(int limit)
        {
            for (int i = 2; i <= limit; i++)
            {
                if (IsPrime(i)==true && callbacks != null) // 그리고 여기서 callbacks가 null이 아닌 조건을 추가한 이유가 무엇인가요??
                {

                    //
                    callbacks(this, new PrimeCallbackArg(i));
                }
            }
        }
        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 int Sum;


        static void PrintPrime(object sender,CallbackArg arg)
        {
            Console.Write((arg as PrimeCallbackArg).Prime + ",");// 이 부분에서 arg 변수를 PrimeCallbackArg으로 형변환 했는데 왜 해야하는 것인가요??
        }



        static void SumPrime(object sender, CallbackArg arg)
        {
            Sum += (arg as PrimeCallbackArg).Prime; // 이 부분에서 Prime을 Sum에다가 추가를 했는데 이건 메서드의 추가인건가요?? 아니면 그냥 단순히 숫자의 증가를 의미하는 건가요??
        }


        static void Main(string[] args)
        {
            PrimeGenerator gen = new PrimeGenerator();
            PrimeGenerator.PrimeDelegate callprint = PrintPrime;
            gen.AddDelegate(callprint); // 이 부분이 gen이라는 것에 PrintPrime 기능을 추가하기 위한 것인가요??

            PrimeGenerator.PrimeDelegate callsum = SumPrime;
            gen.AddDelegate(callsum); // 이부분도 gen이라는 것에 SumPrime을 추가하기 위한 것인가요?

            gen.Run(10);
            Console.WriteLine();
            Console.WriteLine(Sum);

            gen.RemoveDelegate(callsum); //여기서 SumPrime기능을 제거하기위해서 작성한 것이고 아래는 그 결과를 출력하기 위한 것 같은데 왜 제거한 것인가요? 제거를 하면 어느 부분에서 달라지는 건가요? 아래 부분은 위에 기능을 제거를 안한 것과 출력결과가 똑같은 것 같은데 말이죠;
            gen.Run(15);
        }
    }
}








[최초 등록일: ]
[최종 수정일: 1/11/2017]


비밀번호

댓글 작성자
 



2017-01-11 12시47분
[김철환] 추가적으로 EventArgs를 Go to Defintion 해보면 전부 함수 몸체는 비어있고 한가지 특이한점은 함수 정의 상단에 보면 [ComVisible(true)]같은 특성이 달려있던데 이거에 관해서는 책에서 특성은 주석과 같은 설명하는 것이라고 알고 있는데 혹시 어떠한 기능을 하는 건가요? 그리고 기능을 한다면 어떤식으로 작동하는 것인가요? 함수 내부는 텅비어있는데 이걸 가져다 쓴다는 건 말이 안되는 것 같아서 궁금해서 질문합니다.. 그리고 특성[]Attribute의 기능이 단순히 주석과 같은 역할만 하는 것이 아니고 일정한 기능을 하는 것인가요? 그런 기능을 가지게 하려면 어떻게 해야되는 건가요? 대표적으로 알고있는게 [Dllimprot]->dll파일을 불러서 안에 들어있는 함수를 쓰는 것으로 알고 있음. [STAThread] ->자세한 기능은 모르지만 윈폼에서 스레드관련해서 작성하지 않으면 오류난다고 알고는 있음 대략적으로.. 이렇듯 특성이 단순히 주석같은 역할이 아니고 어떠한 기능을 가지게 할수 있는 것 같은데 혹시 이 관련해서 책에나와있는 건가요??
[guest]
2017-01-11 12시49분
[김철환] 실질적인 함수 구현 부분이 어디에 있는지를 알고 싶습니다. 댓글의 질문의 요지는... 그곳이 닷넷프레임워크에 구현되어있다면 어떻게 볼수있는 것인지 혹은 특성이라면 어떤식으로 되어있는것인지... 몸체는 없는데 기능은 해서 이상해서 질문했습니다
[guest]
2017-01-11 01시10분
1. CallbackArg의 구현이 비어 있는 것은, 단지 형변환의 최상위 객체로써만 동작하면 충분하기 때문입니다. 실제로 EventArgs가 그런 경우에 해당하고 현업에서도 EventArgs를 그냥 쓰는 경우도 있지만 대개의 경우 유의미한 값을 전달하기 위해 EventArgs를 상속받은 타입을 별도로 정의해 사용합니다.

2. PrimeDelegate에 CallbackArg를 사용한 것은 '느슨한 결합'의 사용 예입니다. 관련해서 225 페이지의 "느슨한 결합"을 함께 보시면 좋습니다. PrimeDelegate의 첫 번째 인자도 object sender로 되어 있는데 이것 역시 마찬가지입니다. 물론, 명시적으로 첫 번째 인자의 타입을 PrimeGenerator로, 두 번째 인자의 타입을 PrimeCallbackArg로 사용해도 됩니다. 이렇게 한 이유는 닷넷 프레임워크의 Windows Forms 관련한 이벤트 핸들러의 처리가 그런 방식으로 되어 있기 때문입니다. (나중에 윈도우 프로그래밍을 하시게 되었을 때 이 부분을 다시 보시면 그 이유를 이해하시게 될 것입니다.)

3. callbacks(this, new PrimeCallbackArg(I)); 이 코드가 바로 호출 부분입니다. 이에 대해서는 앞으로 다시 가셔서 196페이지의 "4.5.1.3 델리게이트" 부분을 다시 복습하시면 도움의 될 것입니다.

4. callbacks의 null 조건을 추가한 것은, PrimeGenerator의 코드를 보시면 AddDelegate를 호출하지 않는 한 callbacks의 값이 null이기 때문입니다. 만약 AddDelegate를 호출하지 않은 체로 Run 메서드가 불리면 그런 상황에서는 null에 대한 콜백을 호출하는 것이므로 오류가 발생합니다.

5. 당연히 arg 변수를 형변환하지 않으면 Prime 속성에 대해 접근할 수 없습니다. (형변환 하지 않고 한번 컴파일 해보시면 이해가 될 것입니다.)

6. Sum은 int Sum 변수이기 때문에 그냥 값을 더해 준 것에 불과합니다. 메서드의 추가같은 것은 없습니다.

7. gen.AddDelegate(callprint)와 callsum을 해준 것은 콜백 메서드를 추가한 것입니다. 이 부분에 대한 이해도 196페이지의 "4.5.1.3 델리게이트"를 다시 복습하시면 도움이 되실 것입니다.

8. 제거를 한 이유는 실제 제거가 되었는지를 확인하라는 용도로 그렇게 한 것입니다. 그 외의 의미는 없습니다. callsum만 제거되었을 뿐 callprint는 여전히 있다는 것을 실습할 수 있도록 작성된 것입니다.
정성태
2017-01-11 01시14분
1. ComVisible에 대해서는 지금 단계에서 알려고 하기에는 난관이 많으니 잊고 가는 것이 좋습니다. (Windows 환경에서의 COM 이라는 기술을 알아야 합니다.)

2. 특성에 대해서는 이후에도 (271페이지와 563페이지) 계속 설명하고 있기 때문에 그것을 다 보고 다시 질문한 것이 좋겠습니다.
정성태
2017-01-11 01시17분
실질적인 함수 구현 부분은 STAThread나 DllImport의 처리를 의미하는 것 같은데, 그런 특성은 C# 컴파일러가 사용하므로 Roslyn과 같은 오픈소스 C# 컴파일러의 소스 코드 내에서 확인할 수 있습니다. (물론, 분석이 어렵습니다.)

그보다는 위의 답변에서도 언급했지만, 271페이지와 563페이지 등에서 특성에 관한 설명을 계속하고 있기 때문에 그 이후에 다시 질문하는 것이 의미가 있습니다.
정성태
2017-01-11 01시28분
[김철환] 답변 감사합니다 댓글 내용을 다시한번 생각해보고 질문하도록 하겠습니다
[guest]
2017-01-12 05시44분
[김철환] 1. CallbackArg의 구현이 비어 있는 것은, 단지 형변환의 최상위 객체로써만 동작하면 충분하기 때문입니다. 실제로 EventArgs가 그런 경우에 해당하고 현업에서도 EventArgs를 그냥 쓰는 경우도 있지만 대개의 경우 유의미한 값을 전달하기 위해 EventArgs를 상속받은 타입을 별도로 정의해 사용합니다.

' CallbackArg의 구현이 비어 있는 것은, 단지 형변환의 최상위 객체로써만 동작하면 충분하기 때문입니다' 부분에서 이해가 안되서 질문을 합니다. 비어있는 클래스를 상속하는 것이 자식클래스를 암시적 형변환하기 위해 상속을 하는 것인가요??
[guest]
2017-01-12 09시53분
[spowner] 제가 대신 답변을 드리자면,

성태님이 답변주신, 2번의 내용인 '느슨한 결합'으로 이해하시면 됩니다. CallbackArg이 아닌 PrimeCallbackArg으로 넘길 경우, PrimeCallbackArg라는 강한 결합이 발생합니다. 만약 Prime2CallbackArg 이라는 인자가 새로 추가되었다고 했을 때 동일한 delegate로 처리할 수 없습니다. 반면, PrimeCallbackArg대신 CallbackArg를 사용하게 되면, CallbackArg에서 상속받는 클래스 모두 사용할 수 있기 때문에 delegate를 변경할 필요가 없습니다.

그 말은 즉슨, .NET에서 사용하는 이벤트 기본 인자가 EventArgs이고, 이 클래스를 상속받아 구현한 모든 대상 역시 EventHandler 딜리게이트로 처리 가능하다라는 것과 같은 개념입니다.
※ EventHandler<CustomEventArgs>로 EventArgs를 확장하여 이벤트를 사용하는게 어떨 때는 더 낫기도 합니다.

저는 '암시적 형변환'이 아니라고 생각합니다. 형이 변환되는게 아니라 그 형으로 '바라본다'가 정확한 표현일것 같습니다. 그 클래스가 구현한 인터페이스나, 상위 클래스로 '바라볼 수' 있습니다. 인스턴스 자체가 변하는게 아니거든요
[guest]
2017-01-12 11시00분
[김철환] spowner님 답변감사합니다 그런데 또 궁금한점이 있는데요 느슨한 결합을 할때 p.226에 IPower를 interface로 해서 Monitor가 상속을 받고 있는데 이거 처럼 위에 CallbackArg도 interface로 해도 상관없지 않는가요?? 예제를 interface로 바꿔보니 실행은 잘되더군요...어짜피 객체를 생성할필요는 없으니까 말이죠.. 틀린점이 있으면 지적해주시기 바랍니다.
[guest]
2017-01-12 11시29분
[spowner] @김철환

틀린점 없습니다. 상위클래스건, 인터페이스건 "암시적 참조 변환"의 대상입니다. (MSDN에서는 암시적 참조 변환이라고 표현하네요. https://msdn.microsoft.com/ko-kr/library/aa691284(v=vs.71).aspx) 단, 타입이 바뀌는 암시적/명시적 변환 하고는 구분해야 할 것 같습니다

단, 인터페이스는 인터페이스의 기능들로 해당 인스턴스를 사용하겠다라는 것이고, 상위클래스는 좀더 추상적인 관점으로 해당 인스턴스를 사용하겠다라는 개념적인 차이가 있습니다
[guest]
2017-01-12 11시32분
[spowner] @김철환

한가지 더 부연하자면, class건 interface건 인스턴스화 해야 쓸 수 있습니다. 말씀하신 "...어짜피 객체를 생성할필요는 없으니까..."에 대한 부연 설명입니다. 객체를 생성하는 것이 인스턴스화 하는 것이라면 둘 다 해야 합니다. 객체를 생성하는 것이 class를 정의하는 말씀이라면, interface로 교체해도 됩니다. 단, 사용하는 관점이 틀리다는 것은 위에 설명드렸습니다
[guest]

... [31]  32  33  34  35  36  37  38  39  40  41  42  43  44  45  ...
NoWriterDateCnt.TitleFile(s)
5099WPF12/12/201810136안녕하세요. WPF에서 UWP Control을 참조하려고 합니다. [3]파일 다운로드1
5097sdh12/10/201811232[c#] 라이선스 파일 만들기 질문 드립니다. [3]
5096거북이12/3/20186994프로젝트 구성을 참고할 만한 자료가 있을까요? [1]
5095한대현11/21/20187693안녕하세요 c# 설치 파일 빌드중 오류가 생겨서 문의 드려요 [1]파일 다운로드2
5094하주형11/20/20187335안녕하세요 C# using 예약어관련 질문드립니다. [1]
5093Medi...11/19/201810753안녕하세요. wpf Mediaelement 질문 있습니다. [3]
5092하주형11/17/20187284안녕하세요 c# 7.1책 스택관련 질문드립니다. [2]
5091아짱11/15/20188279UWP 개발중 질문이 있습니다. [3]
5090황윤하11/15/201812018c# Socket Server에 접근할 수 있는 client 개수 제한 [5]
5089문성운11/14/20189725uwp에서 TcpListener를 사용할 수 없나요? [5]
5088안중언11/10/20187399TCP 소켓 [1]파일 다운로드1
5084김광흠11/9/20189093사운드 파일 "filename.wav" 와 같은 특정 파일이 실행되는것을 감시하고 싶습니다. [3]
5083거북이11/4/20189443타입의 범위를 넘어서는 연산의 개념을 모르겠습니다. [4]
5082꾸엉11/1/20187495BCL 타입을 모아둔 곳이 있나요? [2]
5081꾸엉10/31/20187625C# 7.1 235p 질문입니다. [3]
5080WPF초보10/30/20189159[WPF] IsManipulationEnabled속성 설정시 Click이벤트 문의 [1]
5079jhp10/30/20188809이 소스에 API후킹 소스를 추가하고 싶은데 어떻게 해야될지 모르겠어요. [4]
5078꾸엉10/29/20187122C# 7.1 185~187p 질문입니다. [2]
5077윤현수10/29/201813528setup파일 설치 이후 실행이 안되는 현상 [11]
5074진우10/28/20187209C# 생성과 동시에 초기화 하는 코드 문의 [2]
5073돌고래10/27/20187297c# 공부 방향 질문 드립니다. [3]
5072엔벌잉10/24/20187825C# textbox, button질문입니다! [4]파일 다운로드1
5071엔벌잉10/23/20188217C#윈도우폼 질문입니다!! [2]
5070진우10/17/20188199Visual Studio 서비스팩과 업데이트 차이 문의 [2]
5069감자10/12/20188884빌드 구성을 재설정하는 방법이 있을까요? [1]파일 다운로드1
5068누오10/10/20187652ASP Core 2.0 에서 dll안에 있는 뷰 읽어들이는 방법? [1]
... [31]  32  33  34  35  36  37  38  39  40  41  42  43  44  45  ...