블로그 이미지
Every unexpected event is a path to learning for you. blueasa

카테고리

분류 전체보기 (2794)
Unity3D (852)
Programming (478)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (185)
협업 (11)
3DS Max (3)
Game (12)
Utility (68)
Etc (98)
Link (32)
Portfolio (19)
Subject (90)
iOS,OSX (55)
Android (14)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (3)
Memories (20)
Interest (38)
Thinking (38)
한글 (30)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (18)
Exercise (3)
나만의 맛집 (3)
냥이 (10)
육아 (16)
Total
Today
Yesterday

IME 소스 (한글)

Programming/C/C++ / 2010. 11. 26. 21:58



ime 뭉탱이(module)  날읽어(README) ver 0.01

                     안노라군.
                 TEAM TRINITY.
             http://anoa.wo.to 
             kjm37@hanmail.net
//---------------------------------------------------------------------
적은 허접한 맨트와.. 버그있는 소스로 ime 강좌(같지도 않은)를 써서 
초보 IMER (ime + er)분 들을 나락의 길(?)로 빠트렸던 anoa 군입니다.;

아직도 몇몇 군데의 웹페이지들에 그 글들이 있길래. 너무도 죄송한(이라고 
쓰고 쪽팔린 이라고 읽는다.) 마음에.. 최종버전 소스를 정리해서 올립니다.


이번엔 강좌대신 상세한 주석(이라고 쓰고 게으름이라고 읽는다)으로 때웁니다.


          2003. 2. 16.
           class 청소부.  아노아군.

//---------------------------------------------------------------------
 소스
//---------------------------------------------------------------------
 프로젝트  : vc.net (vc 7.0) 
 마지막 업데이트 : 2003 년 2월 17일.
 소스의 기능  : IME 입력 및.. 특수문자(한자)의 목록 얻어내기.
      커서 기능 추가. (멀티라인은 지원하지 않습니다.)
 프로젝트구성 : ime
      +- BASE
       +- Error.h  // 에러 메세지용 헤더
       +- Main.cpp  // WinMain 및 프록시져.
       +- Main.h
       +- stdafx.cpp
       +- stdafx.h  // 프리컴파일헤더
      +- IME
       +- ImeBox.cpp // 각각의 ImeBox.
       +- ImeBox.h
       +- Ime.cpp  // ImeBase
       +- Ime.h
      +- Document
       +- ReadMe.txt // 지금 이문서.

//---------------------------------------------------------------------
 사용방법.
file://---------------------------------------------------------------------

 . 주석을 읽기가 귀찮으신분은 ImeBox.cpp ImeBox.h ime.cpp ime.h 를 그대로
가져다 쓰시고 main.cpp 부분을 참고하셔서 붙이시길 바랍니다.

 . 한국어외의 다른 ime 입력을 보장하지 않습니다.. (수고하세요)
 
 . ime 특유의.. 입력 오류시 띵띵~ 거리는 소리를 없에실 좋은 아이디어가 있
    으신 분은 연락을 주세요.

 . 소스를 편집 및 재배포 할시에는 연락을(홈페이지) 해주세용~♡ 재배포시
  에는 본문서에 하나의 파트를 만드시고.. 소스의 구성이나 편집한 부분.
  아직 해야할부분. 작성자 등을 남겨주세요.


//---------------------------------------------------------------------
 버전(버진 아님. -//-)
file://---------------------------------------------------------------------
v 0.1    kwonil 님의 도움으로.. 조합중이던 문자를 날렸음. - _-)V



출처 : http://blog.naver.com/cpp2angel?Redirect=Log&logNo=100007002652

[출처] IME 소스 (한글)|작성자 아발롱


반응형

'Programming > C/C++' 카테고리의 다른 글

ifdef, if defined, ifndef, if !defined  (0) 2011.03.04
enum, 보다 나은 enum  (0) 2011.01.13
[C++] 형변환 (Typecasting) - const_cast, reinterpret_cast, static_cast, dynamic_cast  (0) 2010.09.28
GameLoop (번역)  (0) 2010.09.16
IME 관련  (0) 2010.09.10
Posted by blueasa
, |

Arrays in C++/CLI

Programming/C++/CLI / 2010. 11. 26. 16:00
The article exposes the new array syntax available in C++/CLI for the declaration and use of CLI arrays

Introduction

Managed arrays are allocated on the CLI heap as opposed to native arrays which are allocated on the unmanaged C++ heap, which essentially means that they are typical garbage collected .NET objects. And throughout this article the term array will refer to a managed array, and if at all a native array is mentioned, it will explicitly be termed as a native array. Some of you might have seen my article on using managed arrays with the old MC++ syntax and I am sure a few of you would have let out pained groans at the really peculiar syntax. Well, those people should be delighted to know that C++/CLI supports managed arrays using a far more intuitive syntax than which existed in the older syntax.

Basic features

Here are some of the basic features of managed arrays in C++/CLI :-

  • Syntax resembles that of C++ templates
  • System::Array is automatic base type for all managed arrays
  • Allocated on the CLR heap (means they get Garbage Collected)
  • Rank of the array need not be 1 (arrays with rank 1 are called single dimensional and those with rank >1 are called multi dimensional)
  • Easily supports jagged arrays (unlike in the older syntax, jagged arrays are easier to declare and use)
  • Implicit conversion to and explicit conversion from System::Array BCL class
  • The rank and dimensions of an array object cannot be changed, once an array has been instantiated

Pseudo-template of an array type

The declaration and usage of array types in C++/CLI seems to use an imaginary template type (there is no such template of course, it�s all VC++ compiler magic) :-

 Collapse
namespace stdcli::language
{
    template<typename T, int rank = 1>
        ref class array : System::Array {};
}

array is declared inside the stdcli::language namespace so as to avoid conflicts with existing source code

Single dimensional array usage

Arrays of a reference type

 Collapse
ref class R
{
public:
    void Test1(int x)
    {
        array<String^>^ strarray = gcnew array<String^>(x);
        for(int i=0; i<x; i++)
            strarray[i] = String::Concat("Number ",i.ToString());
        for(int i=0; i<x; i++)
            Console::WriteLine(strarray[i]);
    }
};

The syntax does look different from that used for native arrays; C++ coders who have used templates should find this a lot more intuitive than people who come from a non-C++ background, but eventually they'll get comfortable with it.

Arrays of a value type

 Collapse
ref class R
{
public:
    void Test2(int x)
    {
        array<int>^ strarray = gcnew array<int>(x);
        for(int i=0; i<x; i++)
            strarray[i] = i * 10;
        for(int i=0; i<x; i++)
            Console::WriteLine(strarray[i]);
    }
};

Unlike in the old syntax, array syntax for value types is exactly the same as that for managed types.

Multi dimensional array usage

Multi dimensional arrays are managed arrays that have a rank greater than 1. They are not arrays of arrays (those are jagged arrays).

 Collapse
ref class R
{
public:
    void Test3()
    {
        array<String^,2>^ names = gcnew array<String^,2>(4,2);
        names[0,0] = "John";
        names[1,0] = "Tim";
        names[2,0] = "Nancy";
        names[3,0] = "Anitha";
        for(int i=0; i<4; i++)
            if(i%2==0)
                names[i,1] = "Brown";
            else
                names[i,1] = "Wilson";
        for(int i=0; i<4; i++)
            Console::WriteLine("{0} {1}",names[i,0],names[i,1]);
    }    
};

Jagged arrays

Jagged arrays are non-rectangular, and are actually arrays of arrays. The new template-style array syntax simplifies the declaration and use of jagged arrays, which is a major improvement over the old syntax where jagged arrays had to be artificially simulated by the developer.

 Collapse
ref class R
{
public:
  void Test()
  {
    array<array<int>^>^ arr = gcnew array<array<int>^> (5); 

    for(int i=0, j=10; i<5; i++, j+=10)
    {
      arr[i] = gcnew array<int> (j);
    }

    Console::WriteLine("Rank = {0}; Length = {1}",
      arr->Rank,arr->Length);
    /*
      Output :-
        Rank = 1; Length = 5
    */

    for(int i=0; i<5; i++)
      Console::WriteLine("Rank = {0}; Length = {1}",
        arr[i]->Rank,arr[i]->Length);
    /*
      Output :-
        Rank = 1; Length = 10
        Rank = 1; Length = 20
        Rank = 1; Length = 30
        Rank = 1; Length = 40
        Rank = 1; Length = 50
    */
  }
};

Using a typedef to simplify jagged array usage

 Collapse
typedef array<array<int>^> JaggedInt32Array;
typedef array<array<String^>^> JaggedStringArray;

ref class R
{
public:
    void Test()
    {
        JaggedInt32Array^ intarr = gcnew JaggedInt32Array(10);
        JaggedStringArray^ strarr = gcnew JaggedStringArray(15);        
    }
};

Directly initialize an array

The new syntax allows painless direct initialization of arrays.

 Collapse
ref class R1
{
public:
  void Test()
  {
    //Single dimensional arrays

    array<String^>^ arr1 = gcnew array<String^> {"Nish", "Colin"};
    array<String^>^ arr2 = {"Nish", "Smitha"};
    
    //Multi dimensional arrays

    array<Object^,2> ^ multiobarr = {{"Nish", 100}, {"Jambo", 200}};
  }
};

Arrays as function arguments

 Collapse
ref class R
{
public:
  void ShowStringArray(array<String^>^ strarr)
  {
    for(int i=0; i<strarr->Length; i++)
      Console::WriteLine(strarr[i]);
  }
  void Show2DInt32Array(array<int,2>^ arr)
  {    
    for(int i=0; i<arr->GetLength(0); i++)
    {
      Console::WriteLine("{0} times 2 is {1}",arr[i,0],arr[i,1]);
    }
  }
};

void _tmain()
{
  R^ r = gcnew R();
  r->ShowStringArray(gcnew array<String^> {"hello", "world"});
  array<int,2>^ arr = { {1,2}, {2,4}, {3,6}, {4,8} };
  r->Show2DInt32Array(arr);
}

//Output :-


/*
  hello
  world
  1 times 2 is 2
  2 times 2 is 4
  3 times 2 is 6
  4 times 2 is 8
*/

Returning arrays from functions

 Collapse
ref class R
{
public:
    array<String^>^ GetNames(int count)
    {
        array<String^>^ arr = gcnew array<String^>(count);
        for(int i=0; i<count; i++)
        {
            arr[i] = String::Concat("Mr. ",(i+1).ToString());
        }
        return arr;
    }

    void ShowNames(array<String^>^ arr)
    {
        for(int i=0; i<arr->Length; i++)
            Console::WriteLine(arr[i]);
    }
};

void _tmain()
{
    R^ r = gcnew R();
    array<String^>^ arr = r->GetNames(7);
    r->ShowNames(arr);
}

Array covariance

You can assign an array of type R to an array of type B, where B is a direct or indirect parent of R, and R is a ref class.

 Collapse
ref class R1
{
    //...

};

ref class R2 : R1
{
    //...

};

void _tmain()
{
    array<R1^>^ arr1 = gcnew array<R1^>(4);
    array<R2^>^ arr2 = gcnew array<R2^>(4);    
    
    array<R1^>^ arr3 = arr2;    
    array<R1^>^ arr4 = gcnew array<R2^>(4);    
}

Parameter arrays

C++/CLI has support for parameter arrays. There can only be one such parameter array per function and it also needs to be the last parameter.

 Collapse
ref class R
{
public:
    void Test(String^ s, [ParamArray] array<int>^ arr )    
    {
        Console::Write(s);
        for(int i=0; i<arr->Length; i++)
            Console::Write(" {0}",arr[i]);
        Console::WriteLine();
    }
};

void _tmain()
{
    R^ r = gcnew R();
    r->Test("Nish");
    r->Test("Nish",1);
    r->Test("Nish",1,15);
    r->Test("Nish",1,25,100);
}

Right now the only supported syntax uses the ParamArray attribute, but the eventual syntax will also support the simpler style shown below :-

  • void Test(String^ s, ... array<int>^ arr )

Calling System::Array methods

Since every C++/CLI array is implicitly a System::Array object, we can use System::Arraymethods on CLI arrays.

 Collapse
ref class R
{
public:
  bool CheckName(array<String^>^ strarr, String^ str)
  {
    Array::Sort(strarr);
    return Array::BinarySearch(strarr,str) < 0 ? false : true;
  }
};

void _tmain()
{
  R^ r = gcnew R();
  array<String^>^ strarr = {"Nish","Smitha",
    "Colin","Jambo","Kannan","David","Roger"};  
  Console::WriteLine("Nish is {0}",r->CheckName(strarr,"Nish") ? 
    gcnew String("Present") : gcnew String("Absent"));
  Console::WriteLine("John is {0}",r->CheckName(strarr,"John") ? 
    gcnew String("Present") : gcnew String("Absent"));
}

I've used System::Sort and System::BinarySearch in the above example.

Here's another snippet that clearly demonstrates the implicit conversion to System::Array.

 Collapse
ref class R
{
public:
    void ShowRank(Array^ a)
    {
        Console::WriteLine("Rank is {0}",a->Rank);
    }
};

void _tmain()
{
    R^ r = gcnew R();    
    r->ShowRank( gcnew array<int>(10) );
    r->ShowRank( gcnew array<String^,2>(10,2) );
    r->ShowRank( gcnew array<double,3>(10,3,2) );    
    r->ShowRank( gcnew array<int> {1,2,3} );
    r->ShowRank( gcnew array<int,2> {{1,2}, {2,3}, {3,4}} );
}

Arrays of non-CLI objects

You can declare C++/CLI arrays where the array type is of a non-CLI object. The only inhibition is that the type needs to be a pointer type. Consider the following native C++ class :-

 Collapse
#define Show(x) Console::WriteLine(x)

class N
{
public:
   N()
   {
      Show("N::ctor");
   }
   ~N()
   {
      Show("N::dtor");
   }
};

Now here's how you can declare an array of this type :-

 Collapse
ref class R
{
public:   
   void Test()
   {
      array<N*>^ arr = gcnew array<N*>(3);
      for(int i=0; i<arr->Length; i++)   
         arr[i] = new N();
   }
};

Put this class to use with the following test code :-

 Collapse
void _tmain()
{
   R^ r = gcnew R();
   r->Test();
   Show("Press any key...");
   Console::ReadKey();
}

/* Output:

N::ctor
N::ctor
N::ctor
Press any key...

*/

There, that worked. Of course the destructors for the array elements did not get called, and in fact they won't get called even if a Garbage Collection takes place and the array object is cleaned up. Since they are native objects on the standard C++ heap, they need to have delete called on them individually.

 Collapse
ref class R
{
public:   
   void Test()
   {
      array<N*>^ arr = gcnew array<N*>(3);
      for(int i=0; i<arr->Length; i++)   
         arr[i] = new N();
      for(int i=0; i<arr->Length; i++)   
         delete arr[i];
   }
   //...


/* Output

N::ctor
N::ctor
N::ctor
N::dtor
N::dtor
N::dtor
Press any key...

*/

Ok, that's much better now. Or if you want to avoid calling delete on each object, you can alternatively do something like this :-

 Collapse
ref class R
{
public:   
   void Test()
   {
      N narr[3];
      array<N*>^ arr = gcnew array<N*>(3);
      for(int i=0; i<arr->Length; i++)
         arr[i] = &narr[i];   
   }   
};

This yields similar results to the above snippet. Alternatively you could init the array members in its containing class's constructor and delete them in the destructor, and then use the containing class as an automatic variable (C++/CLI supports deterministic destruction).

Direct manipulation of CLI arrays using native pointers

Here's some code that shows how you can directly manipulate the contents of an array using native pointers. The first sample is for a single dimensional array and the second is for a jagged array.

Natively accessing a single-dimensional array

 Collapse
void Test1()    
{
    array<int>^ arr = gcnew array<int>(3);
    arr[0] = 100;
    arr[1] = 200;
    arr[2] = 300;

    Console::WriteLine(arr[0]);
    Console::WriteLine(arr[1]);
    Console::WriteLine(arr[2]);

    /*
    Output :-
      100
      200
      300
    */

    // Modifying the array using a native int* 

    // that points to a pinned pointer in GC'd heap

    pin_ptr<int> p1 = &arr[0];
    int* p2 = p1;
    while(*p2)
    {           
        (*p2)++;
        p2++;
    }

    Console::WriteLine(arr[0]);
    Console::WriteLine(arr[1]);
    Console::WriteLine(arr[2]);

    /*
    Output :-
      101
      201
      301
    */
} 

Natively accessing a jagged array

 Collapse
void Test2()
{
    array<array<int>^>^ arr = gcnew array<array<int>^>(2);
    arr[0] = gcnew array<int>(2);
    arr[1] = gcnew array<int>(2);
    arr[0][0] = 10;
    arr[0][1] = 100;
    arr[1][0] = 20;
    arr[1][1] = 200;

    Console::WriteLine(arr[0][0]);
    Console::WriteLine(arr[0][1]);
    Console::WriteLine(arr[1][0]);
    Console::WriteLine(arr[1][1]);

    /*
    Output:
      10
      100
      20
      200
    */


    // Copying the managed jagged array to

    // a native array of pointers and accessing

    // the members using the native array

    pin_ptr<int> p1 = &arr[0][0];
    pin_ptr<int> p2 = &arr[1][0];
    int* p3[2];
    p3[0] = p1;
    p3[1] = p2;

    Console::WriteLine(p3[0][0]);
    Console::WriteLine(p3[0][1]);
    Console::WriteLine(p3[1][0]);
    Console::WriteLine(p3[1][1]);

    /*
    Output:
      10
      100
      20
      200
    */

    // Assigning the native array of pointers

    // to a native int** and modifying the array

    int** p4 = p3;
    for(int i=0; i<2; i++)
        for(int j=0; j<2; j++)
            p4[i][j] += 3;          

    Console::WriteLine(arr[0][0]);
    Console::WriteLine(arr[0][1]);
    Console::WriteLine(arr[1][0]);
    Console::WriteLine(arr[1][1]);

    /*
    Output:
      13
      103
      23
      203
    */
}

Essentially we use a pinning pointer to the GC'd heap and then treat the casted native pointer as if it were pointing to a native array. Gives us a really fast method to manipulate array content!

Conclusion

Array syntax in C++/CLI is definitely an aesthetic improvement over the older MC++ syntax, and it also brings in a consistency of syntax that was severely lacking earlier. The template-style syntax should give a natural feel for C++ coders though it might take a little while before you fully get used to it. As usual, I request you to freely post any comments, suggestions, criticism, praise etc. that you might have for me.


출처 : http://www.codeproject.com/KB/mcpp/cppcliarrays.aspx

반응형
Posted by blueasa
, |

조치 방법은 일단 visual Studio IDE 를 삭제하고 다시 설치하는 방법이 있구요..(최악의 방법이자 뒷탈없는 방법이죠.)

 

다음으로는 Visual Studio IDE를 리셋 하는 방법입니다..

관련정보는 http://www.microsoft.com/korea/msdn/library/ko-kr/bb245788(vs.80).aspx

  • Visual Studio 2005의 인스턴스를 모두 종료합니다.
  • 시작을 클릭하고 실행...을 선택합니다.
  • "devenv.exe /resetuserdata"를 입력합니다.
이 명령을 사용하면 몇 분 동안 Visual Studio가 정리되고 처음 상태로 설정됩니다. 이때 작업 관리자를 열어 devenv.exe 프로세스가 실행 중인지 여부를 확인할 수 있습니다. 실행이 종료되면 Visual Studio를 다시 시작할 수 있습니다. 그러면 컴퓨터에서 Visual Studio를 처음으로 실행할 때처럼 처음 실행 대화 상자가 다시 표시됩니다.

반응형
Posted by blueasa
, |

많은 개발업체에서 버전 관리를 위해 무료 버전 관리 프로그램인 Tortoise SVN를 많이 사용하고 있는 걸로 알고 있다.

Tortoise SVN의 장점 중 하나인 현재 상태를 아이콘으로 표시해주는 기능이 있는데, 이 아이콘 상태를 정의하기 위해 Tortoise SVN에서 수시로 디스크를 읽으며, 파일 상태를 체크한다. 이 때문에, 컴퓨터 성능이 저하 되기도 하는데, 범인은 바로 TSVNCache.exe!! 이 프로세서가 백그라운드로 실행되면서, 폴더/파일를 수시로 읽어들이고 있기 때문이다.

Tortoise SVN를 쓰고 있다면, 밑의 방법대로 설정 해두자. 이렇게 하면 사용자가 지정한 폴더와 파일 외에는 접근을 하지 않으므로, 디스크 읽기를 최소화 시킬수 있다.

방법은 이렇다.

1. TortoiseSVN -> Settings 메뉴를 연다 .


2. Look and Feel 트리 항목에서 Icon Overlays 선택
    

3. 그럼 밑의 그림과 같은 항목들이 나온다.



4. 하단에 Exclude Paths(제외항목)에 드라이브명과 함께 *를 찍어준다.
즉, 드라이브내의 모든 파일/폴더를 검색하지 말란소리다.


5. Include Paths에는 버전관리를 하고 있는 폴더명을 적어준다.


6. 설정을 마치면, 작업 관리자를 통해 TSVNCache.exe를 강제 종료시킨다(보통 알아서 재시작한다).

출처: http://kindtis.tistory.com/6

SVN설정 관련: http://tortoisesvn.net/docs/release/TortoiseSVN_en/tsvn-dug-settings.html


[추가]
- 내가 쓰는 1.6.5, Build 16974 버전에서는 'Icon Overlays'항목이 바로 있었음.


반응형
Posted by blueasa
, |
부모 폼과 자식 폼이 있다; 자식 폼에서 A라는 버튼을 클릭했을 때; B라는 텍스트 박스의 내용을 부모 폼의 C라는 텍스트 박스에 표시하고 싶다; 그 방법은?

물론; 가장 간단한 방법은 private으로 선언되어 있는 C라는 텍트스 박스를 public으로 선언하고; 자식 폼에서 직접 이 텍스트 박스에 접근하여; 값을 대입하는 방법이 있습니다;

하지만; 개인적으로 이 방법은 C#이 지향하는 OOP(Object-oriented paradigm)를 위배하고; 깔끔하지 못한 방법으로 별로 권장하고 싶지 않네요;

개인적으로 권장하는 것은 이벤트(event)를 이용하는 것 입니다; 이벤트는 단순히 폼 간의 어떤 데이터를 주고 받을 수 있을 뿐만 아니라; 서로 다른 클래스 간의 데이터 전송에도 유용하며, 데이터를 구조체 형식으로도 넘길 수 있는 등 다양한 장점이 있지요; 무엇보다, OOP를 준수하면서도; 깔끔한 코드를 유지할 수 있다는 것에 후한 점수를 주고 싶군요;

이 이벤트를 구현하는 방법에 가장 핵심이 되는 내용은 바로 delegate 입니다.
C++/MFC, java 등 다른 언어에 능숙한 사람들 대부분이 C#에 금방 적응하게 됨에도 불구하고; 그나마 C#에서 가장 당황하는 개념이 delegate가 아닐까 싶네요; (나만 그런가?;)

delegate는 한글로 굳이 번역하자면; 대리자라고 하는데; C#이 다른 언어와 차별성을 가지는 중요한 몇 몇 이슈 중 하나가 이 녀석의 존재라고 생각합니다;

단어 뜻으로만 이해하자면; 어려우니까; 서두에 언급한 자식 폼에서 부모 폼으로 텍스트를 전달하는 예제를 통해; delegate의 역할을 이해해보죠;

이미 언급했지만; 자식 폼에서 부모 폼으로 데이터를 전달할 때, 이벤트를 이용하기로 하였는데; 이벤트에서 가장 기본적인 사실은; 이벤트를 발생하는 곳이 있으면, 이벤트를 받는 쪽도 있어야 된다는 것입니다;

따라서, 자식 폼에는 이벤트를 발생시키는 녀석을 정의하고, 부모 폼에서는 이벤트를 받는 녀석을 정의해야 된겠지요. 이미 C#을  이용해 윈 폼 프로그래밍을 해본 사람이라면; 폼에 버튼을 붙이고; 클릭 이벤트를 추가해서; 버튼을 클릭하면; 메시지 박스로 "Hello, World!" 정도는 경험이 있을 것 입니다;

이 때, 버튼도 우리가 예로 들려는 자식 폼과 같습니다; 버튼이 이벤트를 발생시키고, 부모 폼에서 버튼 이벤트를 받아, 거기서 메시지 박스를 띄운 것이기 때문이지요;

자 이벤트를 정의하는 과정은 다음과 같습니다;
사용자 삽입 이미지

클래스 ChildFormEventArgs는 이벤트 데이터가 들어 있는 클래스에 대한 기본 클래스인 EventArgs를 상속 받아 구현하였습니다. 우리는 자식 폼에서 부모 폼으로 텍스트를 전송할 목적이므로, 기본 클래스에 message란 속성을 추가하였구요;

그리고 그 아래 이벤트 대리자(delegate)를 선언하는데, 대리자를 통해 넘기는 파라미터에 주목해봅시다;
ChildFormEventArgs는 앞에 언급한대로 이벤트 데이터 이고, object sender는 뭘까요?

이벤트를 발생 시킨 주체입니다; 우리의 예에서는 바로 자식폼이 되겠지요;

이벤트를 위한 대리자를 선언했으면; 자식 폼에 이 이벤트를 발생시키기 위한 코드를 구현해야 합니다;
사용자 삽입 이미지

이벤트 선언부를 눈여겨 보세요;

이에 앞서 선언한 delegate에 이벤트를 위한 엑세스 한정자인 event를 붙였습니다; 그리고 파생 클래스에서 이 이벤트를 일으키거나 override 할 수 있도록 protected와 virtual 키워드를 붙였지요;

그리고 그 아래 정의된 메소드는 자식 폼에 추가한 버튼을 클릭하면 호출되는 녀석; 이미 알고 있듯이; 우리는 버튼을 클릭했을 때, 자식 폼에 있는 텍스트 박스(txtSentMessage)에 적힌 텍스트를 부모 폼에 전달하기 위함이므로; 앞서 정의한 event를 발생시킬 수 있는 NotifyEvent를 호출하도록 하였습니다;

그럼, 이제 부모 폼에서 이벤트를 받을 수 있도록 구현해보죠;
사용자 삽입 이미지

부모 폼의 생성자(constructor)에 자식폼의 메모리를 할당하고; 이벤트를 받기 위해 OnNotifyParent이벤트 핸들러를 추가합니다;

자, 여기서 대리자(delegate)의 역할을 이해할 수 있습니다. 자식 폼에서는 결코 부모 폼의 child_OnNotifyParent 메소드를 직접적으로 호출하지 않습니다. 단지, 이벤트로 정의한 OnNotifyParent(delegate)를 구현하였고; 이를 이용해 이벤트를 발생시키는 NotifyEvent 메소드만 구현했을 뿐이지요; 하지만 OnNotifyParent는 대리자란 명칭에 걸맞게; NotifyEvent가 호출되면; 간접적으로 child_OnNotifyParent 해줬습니다;

이 때 이벤트 데이터를 전달해주는 ChildFormEventArgs를 통해 자식폼의 텍스트 박스에 적힌 텍스트를 가져올 수 있네요;

다시, 정리하자면 이렇습니다.
1. 이벤트는 이벤트를 발생시키는 곳이 있으면, 발생한 이벤트를 듣는 곳도 있다;
2. 이벤트는 이벤트를 발생시키는 곳과 발생한 이벤트를 듣는 곳을 잇기 위한 대리자(delegate)로 구현한다.

delegate란 개념은 단지; 이벤트를 구현할 때만 쓰이지 않습니다; 제가 오래 전에 블로그에 쓴 C#에서 크로스 쓰레드 문제에서도 언급된 적이 있습니다. 사실 저도 저 때 delegate 개념이 구체화 되지는 않았습니다; 어렴풋이 이해만 했었고; 단지 저런 상황이 생기면; 다시 써먹기 위해 남겼을 뿐이지요..;

혹시나 필요하신 분들이 있을까; 아티클에 설명한 예제의 소스 코드를 첨부합니다;



반응형
Posted by blueasa
, |
C++을 사용하시는 분들은 VC계열에서 전처리자을 이용하는 방법에 대해서 익숙하신 분들이 많으실겁니다. 
특히 전처리자, #define, #if ~ #endif등을 이용해서 디버그할때만 필요한 코드를 릴리즈할때 무시하도록 하는 일은 한번쯤은 해보셨지 않았나 싶습니다. 

C#으로 넘어오면서 네임스페이스등의 개념이 본격적으로 사용되고 전처리자를 잘 사용하지 않게 되었습니다. 하지만 코드를 짜다보니 여전히 디버그용으로 만든 코드가 릴리즈에 포함되지 않게 하는일이 필요하더군요. 그래서 어떻게 쓸수있지 않을까 고민하던 중에 다음과 같은방법을 발견했습니다. 

using System; 
using System.Diagnostics; 

class Program { 
    static void Main(string[] args) { 

        #if DEBUG 
        DebugMethod1(); 
        #endif 

        DebugMethod2(); 
        Console.ReadKey(); 
    } 
    static void DebugMethod1() { 
        Console.WriteLine("Debug1"); 
    } 

    [Conditional("DEBUG")] 
    static void DebugMethod2() { 
        Console.WriteLine("Debug2"); 
    } 
}

from : Eric Gunnerson's C# Compendium
         http://blogs.msdn.com/ericgu/archive/2004/08/13/214175.aspx


빨갛게 된 부분을 주목해주세요, 위의 전처리자를 이용한 방법은 코드라인 일부를 디버그 모드에서 활성화하기 위해 감싸는 것입니다. VS에서 릴리즈 모드 컴파일로 들어가면 위 전처리자 사이의 코드는 회색으로 변하면서 실행이 안됩니다. 아래 Attribute를 사용하는 방법은 메소드 전체를 디버그모드에서만 컴파일 하기 위해 사용하는 것입니다. 이러한 팁은 매우 간단하지만 많은 분들이 모르시더라구요... 역시 구글검색은 안나오는게 없는것 같습니다. ^^

 좀더 덧붙이자면, C#에는 전처리 과정이 없기 때문에 컴파일 과정에서 무시되는것 같습니다. 그리고 뒤의 Attribute를 사용하는 방법은 문제가 있는데 함수의 return값이 void 이어야만 하고 public 메소드를 저렇게 만들게 되면 나중에 잡기힘든 버그가 발생 (분명 실행시켰는데 실행조차 안되는) 한답니다. 참고하세요.


반응형
Posted by blueasa
, |

[펌] Getter/Setter 없는 삶

Etc / 2010. 11. 10. 19:29
실전 코드로 배우는 실용주의 디자인 패턴 - 10점
앨런 홀럽 지음, 송치형 옮김/사이텍미디어(희중당)

요즘 출퇴근시에 이 책을 읽으면서 많은 것을 깨닫고 있습니다. 지금까지 제가 한 코딩 방식은 객체 지향이 아니었습니다. 으헉!! 초반부에 Get과 Set의 접근/수정 메소드에 대한 이야기가 나오더군요. 요근래 다른 개발자 분들의 블로그에서도 관련 이슈를 보긴 봤는데 ( Get/Set을 쓰지말자는 ) 그다지 수긍이 가지 않았습니다. 그렇게까지 해야 하나? 라는 기분이었죠. 하지만 위 책에서의 내용을 보자니 오호~ 라는 감탄사가 나오더군요. 내용이 굉장히 설득력 있고 타당한 이유와 예시를 제시해주는데 확 와닿더군요. ( 덕분에 제 프로젝트도 리팩토링 들어갔습니다 )

책에서 나오는 Get/Set에 대한 정리를 나열해보자면...

객체는 내부 데이터와 구현을 노출시키면 안된다. 접근 메소드와 수정 메소드는 내부 데이터와 구현을 노출시키므로 유지 보수에 악영향을 미치며, 가능한 사용하지 말아야 한다.

필드를 Private로 만들고 Public Get/Set 메소드를 추가하는 것은 코드를 복잡하게 만들 뿐 대게 아무런 이득도 없다.

객체들 간의 관계를 세심히 디자인 하였다면 대부분의 클래스는 Get/Set 메소드를 필요로 하지 않는다.

구현 은닉이 제대로 되어 있는가? 즉, 클래스의 구현 방식을 마음대로 바꾸어도 외부에 영향을 미치지 않는가?

어던 작업을 수행하는데 필요한 정보를 요구하지 말라. 대신 정보를 갖고 있는 객체에 일을 해달라고 부탁하라.

즉, 이런식으로 코딩을 하라는 겁니다.
1 // 잘못된 예
2 // get과 set으로 내부 데이터 노출
3 Money a, b, c;
4 a.setvalue( b.getvalue + c.getvalue );
5   
6 // 잘된 예
7 // Money 객체에 일을 해달라고 요청하라.
8 Money a, b;
9 a.increaseBy( b );
극단적인 예로 int형을 반환하는 get 메소드를 호출 하는 곳이 1,000 곳이 있는데, 프로그램 수정으로 인해 반환 타입을 long으로 바꾸게 되면 get 메소드를 호출 하는 1,000곳을 모두 수정해야 하는 사태가 발생되죠. 하지만, get을 쓰지 않고 해당 객체에 일을 해달라고 요청하는 형태로 메소드를 수정 하면, 반환 타입이 바뀌더라도 클래스 내부만 수정하면 되니 유지보수가 훨씬 수월해지는 것 입니다.

말로 표현 하자면 "이 속성 값을 줘. 그래야 내가 그 것을 출력할 수 있어" 라고 하지 말고, "이 속성을 출력해줘" 라고 하는 거죠.

처음 C++을 배우며 객체 지향에 대해 공부할때 데이터 은닉에 대해 보긴 봤지만 이렇게까지 의식하면서 코딩을 하지않았죠. 정말 아무런 생각없이 Get/Set을 써왔는데, 이제는 다르게 써봐야겠습니다. 


반응형
Posted by blueasa
, |
툴작업을 하다보면 Native C++에서 Managed C++에 접근해야 할 필요가 있다.
정확히 말해서 두 영역간의 소통이 필요할때가 있다.

예로 현재 작업 중인 툴에서 C#에 만들어진 Log 폼 다이얼로그에 로그를 찍고 싶을 때, Native C++에서 어떻게 작업을 해야할까?
Native C++에서는 Managed C++ 코드를 사용하거나 함수를 호출할수도 없다.
해결 방법 중 하나는 클래스 상속과 다형성을 이용하는 방법이다.

먼저 Native C++에서 밑의 코드와 같이 정의해준다

// 로그 클래스
class CLog
{
public:
        virtual void Print( const char* str ) = 0;
};

// 로그를 사용할 클래스
class CFramework
{
public:
        void SetLogger( ae_CLog* log ) { m_pLogger = log; }
private:
        CLog* m_pLogger;
}

그 다음 랩핑 클래스에서 위에서 정의한 CLog 클래스를 상속 받아 자식 클래스를 하나 만든다

public class ManagedLogger : public CLog
{
public:
        virtual void Print( const char* str )
        {
                // 이곳에 C#에서 수행할 작업을 코딩한다.
                // 이곳은 Unamanaged 영역이므로, 바로 Managed 코드를 못 쓴다.
                // 그러니 Managed 클래스에서 Static 함수를 만들어 여기서 호출해준다
                // 예) CFrameworkWrapper::WriteLog( str );
        }
};

주의할점은 주석에 적어놓았다. Managed 코드와 UnManaged 코드는 혼용될수 없으므로, 오로지 함수로만 통신을 해야한다.
자식 클래스를 정의 하였으면, 이제 이것을 사용해보자.

void CFrameworkWrapper::Create()
{
        m_pFrameWork = new CFramework();
        m_pFrameWork->SetLogger( new ManagedLogger() );
}

Native C++의 CFramework를 선언해주고, SetLogger 함수에 ManagedLogger 클래스의 객체 포인터를 넘겨주고 있다. ManagedLogger는 CLog 클래스를 상속받은 클래스 이므로, CLog 클래스로도 ManagedLogger 클래스를 가리킬수 있다. 이젠, 가상함수를 통해 Native C++ 영역에서 ManagedLogger의 함수를 호출할수 있는 것이다.


반응형
Posted by blueasa
, |

Dot Net Perls

Link / 2010. 11. 8. 15:19
반응형

'Link' 카테고리의 다른 글

Download D3DX DLLs (d3dx9_xx.dll, d3dx10_xx.dll)  (0) 2010.12.23
종이천하  (0) 2010.12.20
CppCheck(소스 결함 예방 툴)  (0) 2010.10.06
C# 관련 블로그  (0) 2010.08.18
Visual Assist X 관련 링크~  (0) 2010.06.21
Posted by blueasa
, |

You want to use Dictionary in your C# program for constant lookup times and to associate keys with values. Look at some examples of using Dictionary with Keys and KeyValuePair, as well as with classes and methods. This document has tips and examples for using Dictionary with keys and values using the C# programming language.

Dictionary provides fast lookup of elements.
Used when you have many different elements.
Found in the System.Collections.Generic namespace.
Specify the types of its keys and values.

Adding keys

To get started, let's add four keys with values to a Dictionary instance. Afterwards, we look inside the Dictionary using Visual Studio's debugger. You will see that the Dictionary is composed of separate keys and values. Here's the Dictionary code and then its internal view.

~~~ Program that uses Dictionary Add method (C#) ~~~

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        Dictionary<string, int> d = new Dictionary<string, int>();
        d.Add("cat", 2);
        d.Add("dog", 1);
        d.Add("llama", 0);
        d.Add("iguana", -1);
    }
}

Inside the Dictionary. Here's what the above code looks like in memory. It is represented by a collection of key and value pairs. The screenshot is worth looking at. This article is based on .NET 3.5 SP1, but the contents apply to other versions as well.

Dictionary internals

Looking up values

Here we see how you can check to see if a given string is present in a Dictionary with string keys. We look at more types of Dictionaries further on, but here is the ContainsKey method.

=== Program that uses ContainsKey (C#) ===

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        Dictionary<string, int> d = new Dictionary<string, int>();
        d.Add("apple", 1);
        d.Add("windows", 5);

        // See if Dictionary contains this string
        if (d.ContainsKey("apple")) // True
        {
            int v = d["apple"];
            Console.WriteLine(v);
        }

        // See if Dictionary contains this string
        if (d.ContainsKey("acorn"))
        {
            Console.WriteLine(false); // Nope
        }
    }
}

=== Output of the program ===

1

Note on efficiency. There is a more efficient method called TryGetValue on the Dictionary class, and you should definitely use it when possible. As its name implies, it tests for the key and then returns the value if it finds the key.

See TryGetValue Method.

KeyNotFoundException

If you are running into the KeyNotFoundException, you are accessing a key in your Dictionary that doesn't exist. Dictionary is not the same as Hashtable and you must test keys for existence first, with ContainsKey or TryGetValue.

See KeyNotFoundException Fix.

Understanding KeyValuePair

Hint: this is not in every beginner's C# book. When Dictionary, or any object that implements IDictionary, is used in a foreach loop, it returns an enumeration. In the case of Dictionary, this enumeration is in the form of KeyValuePairs.

See KeyValuePair Collection Hints.

Using foreach on Dictionary

Here we use foreach syntax and KeyValuePair generics in the foreach loop. With collections like Dictionary, we must always know the value types. With each KeyValuePair, there is a Key member and Value member.

=== Program that uses foreach on Dictionary (C#) ===

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Example Dictionary again
        Dictionary<string, int> d = new Dictionary<string, int>()
        {
            {"cat", 2},
            {"dog", 1},
            {"llama", 0},
            {"iguana", -1}
        };
        // Loop over pairs with foreach
        foreach (KeyValuePair<string, int> pair in d)
        {
            Console.WriteLine("{0}, {1}",
                pair.Key,
                pair.Value);
        }
        // Use var keyword to enumerate dictionary
        foreach (var pair in d)
        {
            Console.WriteLine("{0}, {1}",
                pair.Key,
                pair.Value);
        }
    }
}

=== Output of the program ===

cat, 2
dog, 1
llama, 0
iguana, -1

cat, 2
dog, 1
llama, 0
iguana, -1

Overview of the code. The code example declares and populates an example Dictionary. This Dictionary happens to indicate what animals we have and how many of them.

Using the foreach loop. It has a ShowDictionaryPair method. This method demonstrates the foreach loop and the KeyValuePair declaration. Pay careful attention to the syntax in the foreach loop. Each KeyValuePair has two members, pair.Key and pair.Value, which contain string keys and int values.

Using the var keyword. The final loop in the code shows how you can make the syntax for looping really simple by using the var keyword. This is not always desirable on some projects, however.

Getting all Dictionary keys

Here we use the Keys property and then look through each key and lookup the values. This method is slower but has the same results. Using the Keys collection and putting it in an array or List is very effective in other situations.

=== Program that gets Keys from Dictionary (C#) ===

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        Dictionary<string, int> d = new Dictionary<string, int>()
        {
            {"cat", 2},
            {"dog", 1},
            {"llama", 0},
            {"iguana", -1}
        };
        // Store keys in a List
        List<string> list = new List<string>(d.Keys);
        // Loop through list
        foreach (string k in list)
        {
            Console.WriteLine("{0}, {1}",
                k,
                d[k]);
        }
    }
}

=== Output of the program ===

cat, 2
dog, 1
llama, 0
iguana, -1

Benchmarking KeyValuePair usage

Using foreach on KeyValuePairs is several times faster than using Keys. This is probably because the Keys collection is not used. KeyValuePair allows us to simply look through each pair one at a time. This avoids lookups and using the garbage-collected heap for storage.

See Garbage Collection Visualizations.

=== Benchmark for KeyValuePair foreach loop ===

KeyValuePair: 125 ms
Note:         This loops through the pairs in the Dictionary.

Keys loop:    437 ms
Note:         This gets the Keys, then loops through them.
              It does another lookup for the value.

Note on the benchmark. The author made a small change to the Keys version for clarity and performance, so these figures are only general and apply to the previous version. Using KeyValuePair is most likely still faster.

Sorting your Dictionary values

If you need to sort the values in your Dictionary, you may be perplexed at first and wonder how to order the keys properly. Fortunately, I have an article about how to do this, although it is not optimal.

See Sort Dictionary Values.

Related collections

You will find other collections, such as SortedDictionary, in the base class libraries, BCL, available for you to use. However, my experience is that it is hard to get as good performance as with Dictionary.

See SortedDictionary.

Using different types in Dictionary

Dictionary in C# is a generic class, which means it requires you to specify a type for it to use. So, you can use an int key, just as easily as a string key. Here is an example of a Dictionary with int keys.

=== Program that uses int keys (C#) ===

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Use a dictionary with an int key.
        Dictionary<int, string> dict = new Dictionary<int, string>();
        dict.Add(100, "Bill");
        dict.Add(200, "Steve");
        // You can lookup the int in the dictionary.
        if (dict.ContainsKey(200))
        {
            Console.WriteLine(true);
        }
    }
}

=== Output of the program ===

True

Advanced features of Dictionary. For more advanced developers, you can use the GetHashCode() method and override it to create Dictionaries or hashes with the class. This can improve performance in those cases.

Enhancing lookup speed

To enhance lookup speed on your Dictionary, you can change the size of the keys you use. My research has shown that when you use shorter string keys, the lookup time is improved. This could create more collisions, so testing may be necessary.

Using Dictionary with LINQ

By using the ToDictionary method, which is an extension method on IEnumerable that will place the keys and values into a new Dictionary using lambda expressions.

=== Program that uses LINQ (C#) ===

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        string[] arr = new string[]
        {
            "One",
            "Two"
        };
        var dict = arr.ToDictionary(item => item, item => true);
        foreach (var pair in dict)
        {
            Console.WriteLine("{0}, {1}",
                pair.Key,
                pair.Value);
        }
    }
}

=== Output of the program ===

One, True
Two, True

Explanation of the example. The above example uses ToDictionary, which resides in the System.Linq namespace, on the string[] array to create a lookup table where both strings can be accessed in constant time, O(1).

Using ContainsValue to find values

Dictionary also helpfully implements a method called ContainsValue. This method does not enjoy the constant-time lookup speed that ContainsKey has, however. It instead searches the entire collection, making it linear in complexity.

=== Program that uses ContainsValue (C#) ===

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        Dictionary<string, int> d = new Dictionary<string, int>();
        d.Add("cat", 1);
        d.Add("dog", 2);
        if (d.ContainsValue(1))
        {
            Console.WriteLine(true); // true
        }
    }
}

=== Output of the program ===

True

ContainsValue method. The above example will internally loop through all elements in the Dictionary until it finds the match, or there are no more to check. MSDN: "This method is an O(n) operation, where n is Count."

See ContainsValue Dictionary Example.

Clearing and counting

You can erase all the key/value pairs within your Dictionary by using the Clear() method, which accepts no parameters. Alternatively, you can assign the variable to null. The difference between Clear and null is not important for memory, as in either case the entries are garbage-collected. Internally, I see that Clear calls Array.Clear, which is not managed code.

Counting your Dictionary. The Count method on the Dictionary collection gives you an effective way of computing the total number of keys in the instance. This is much simpler than accessing the Keys property or looping over the Dictionary to count it. This Count property is covered in more detail on this site.

See Count Dictionary, Using Count Property.

Removing an entry

Here you want to eliminate an entry, not just by setting its value to null or string.Empty, but by also removing the key itself. Fortunately, you can use the Remove method.

~~~ Program that uses Remove (C#) ~~~

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        Dictionary<string, int> d = new Dictionary<string, int>();
        d.Add("cat", 1);
        d.Add("dog", 2);

        d.Remove("cat");     // Removes cat
        d.Remove("nothing"); // Doesn't remove anything
    }
}

Execution of the code. Running the code in Visual Studio, no exceptions are thrown, which means that when you remove a key that doesn't exist, nothing happens. However, Remove throws System.ArgumentNullException when it receives a null parameter.

Copying entire Dictionary

The Dictionary class has a useful constructor that allows you to easily copy all the values and keys in your Dictionary into a new Dictionary instance. You can write the logic yourself, but using this constructor improves code reuse and simplicity. This site has more information on the Dictionary copy constructor.

See Copy Dictionary.

Parameters and return values

It is also possible to use the Dictionary constructed type in the C# language as a parameter to methods or as a return value from methods or properties. Because the Dictionary type is defined as a class, it is always passed as a reference type, meaning only 32-64 bits will be copied on the method invocation. The same principles apply when copying a Dictionary return value from a method. You can find more information on Dictionary parameters on this site.

See Dictionary Parameter and Return Value.

Question

Should I use List or Dictionary?

I suggest you almost always use Dictionary when you need to do lookups. If you use List and you need to look up a key, your program may freeze if you happen to have a huge number of elements. In other words, if you use Dictionary, your program can recover from pathological, edge cases.

Using multiple variables in single key

You can sometimes use multiple variables in a key by creating a special function that transforms those variables into a string, serializing them. So, you could use the string "1,2" to mean the ints 1 and 2.

Initializing Dictionary at class level

Sometimes it is useful to have a Dictionary in your class that is allocated at the class level, not in a method or constructor. Additionally, if you have a static class then you should always initialize your Dictionary at the class level like this instead of the static constructor. Static constructors have performance penalties, which I have measured.

=== Program that uses Dictionary with class (C#) ===

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        Example e = new Example();
        Console.WriteLine(e.GetValue());
    }
}

class Example
{
    Dictionary<int, int> _d = new Dictionary<int, int>()
    {
        {1, 1},
        {2, 3}, // <--
        {3, 5},
        {6, 10}
    };
    public int GetValue()
    {
        return _d[2]; // Example only
    }
}

=== Output of the program ===

3

Summary

In this article, we saw how you can use Dictionary with KeyValuePair to look through all pairs in the Dictionary. Additionally, we saw material on ContainsKey, which lets you check key existence. Finally, the author considers Dictionary one of the most interesting subjects in the programming world.

See Dictionary Articles.

© 2007-2010 Sam Allen. All rights reserved.


출처 : http://dotnetperls.com/dictionary-keys

반응형
Posted by blueasa
, |