Monday, May 27, 2013

Closure 쓸 때 주의할 점

지난 포스트에 이어서...

var list = new List<int>(10);
var menu = new ToolStripMenuItem("메뉴");
for(int i=0; i<list.Count; i++) {
     var subMenu = new ToolStripMenuItem("메뉴 항목");
     subMenu.Click += ( (sender, args)=>{ subMenu_Click(sender, i); } ); // closure
}
void subMenu_Click(object sender, int idx)
{
     MessageBox.Show(string.Format("{0}이 클릭됨", idx));
}

예상되는 결과는? i번째 subMenu를 누르면 i가 출력되지 않는다.

다음과 같이 변수를 한 번 복사하는 게 해결책이다:

for(int i=0; i<list.Count; i++) {
     var subMenu = new ToolStripMenuItem("메뉴 항목");
   int j=i; // 이거면 되지 않을까 했는데 진짜 됐음-_-乃
     subMenu.Click += ( (sender, args)=>{ subMenu_Click(sender, j); } ); // closure
}

해결하고 나서 stackoverflow에 질문을 올렸는데

Google: passing parameter evenhandler value changes C#

이걸로 검색하니까 금방 나옴.

역시 원리는 안 찾아보고 하니까 이유는 모른다.

아래 링크에 이유가 있다고 하는데 읽기는 귀찮다.
http://stackoverflow.com/questions/2226510/closures-in-c-sharp-event-handler-delegates
http://stackoverflow.com/questions/271440/c-sharp-captured-variable-in-loop

Sunday, May 26, 2013

Parameter 전달: Capturing Variables with Closures [Event handler]

var cc = new CustomClass();
var menu = new ToolStripMenuItem("메뉴 항목");
menu.Click += ( (sender, args)=>{ edit_Click(sender, cc); } ); // closure

void menu_Click(object sender, CustomClass cc)
{
     cc.DoSomething();  
}

원리는 귀찮아서 안 찾아보고 있는데 어쨌든 편하게 된다.

EventHandler<CustomClass> ...
void menu_Click(object sender, EventArgs<CustomClass> e)
{
    e.
}

이거보단 훨씬 편하다.

Wednesday, May 22, 2013

HashSet

HashSet<T>은 C#에서 Set 대용으로(ie, 중복을 허용하지 않는 컬렉션) 흔히 쓰는데, equality를  hash code를 이용해서 검증하기 때문에 Object.GetHashCode()를 오버라이딩해 주어야 한다.

문제는 어느 인터페이스를 구현할 것인가이다. 구글에서 대충 검색하다 보면 IEqualityComparer<T>와 IEquatable<T>이 나타날 텐데, 감으로는 IEquatable<T>인 것 같지만(맞음) 과연 IEqualityComparer<T>는 무엇인가 하는 궁금증이 생긴다.
   (사실 이 이유만은 아니다. Visual Studio에서 IEquatable의 정의를 따라가 보면,
          bool Equals(T other)
   만 있고 GetHashCode가 없어서 IEquatable<T> 구현 없이
   그냥 Equals와 GetHashCode 를 override하고 말겠다는 생각이 든다...*)

어찌됐든, 두 인터페이스 중 어느 것을 써야 하는가에 대해서는, 아래 문서가 이를 잘 설명하고 있는데, 특히 마지막 답변이 이해하기 쉬운 예제와 함께 잘 설명하고 있다.

http://stackoverflow.com/questions/9316918/what-is-the-difference-between-iequalitycomparert-and-iequatablet

1. class T : IEquatable<T> 형태로 쓴다.
 * class MyClass : IEquatable<T> 형태는 (대개) 의미가 없다.
 * public bool Equals(T other)를 구현하면 된다.
   - Object.Equals(Object o)에 비해서 parameter가 T가 되고(캐스팅이나 as가 필요 없어짐#),
    override 키워드를 안 써도 경고문이 뜨지 않는 장점이 있다. <주>

 * ==, !=, GetHashCode와 nongeneric Equals도 오버라이딩해야 한다.
   - ...라고는 하는데 GetHashCode()만 해도 HashSet을 쓰는 데는 별 문제가 없다(아직까지는...).

2. IEqualityComparer는 특수한 상황에서만 쓰이는 동일성 비교 policy를 만들 때 쓴다. 예를 들어 특정 '조건을 만족하면 같은 것으로 치는' 상황이다. HashSet을 예로 들면, 평소에는 유일성이 인정되는 객체는 무조건 다 받아주다가(Add), 어떤 상황이 되면, 특정 조건을 만족하는 객체는 무조건 받지 않는 것이다.
class Person { 
    public int Age; 
} // Equals를 재정의하지 않았으므로 ReferenceEquals가 호출될 것이다.
class AgeEqualityTester : IEqualityComparer<Person> {
    public bool Equals(Person x, Person y) { return (x.Age==y.Age); }
    public int GetHashCode(Person p) { return p.Age; }
}
var people = new Person[] {new Person {age=23} };
var person = new Person() { age=23 };

var b1 = people.Contains(person); //FALSE;
var b2 = people.Contains(person, new AgeEqualityTester()); //TRUE

여기서 ICollection.Contains() 메서드의 새로운 사용법을 배울 수 있다 :)

Person/People 예는 이해하기는 쉬운데 별로 재미는 없다. 이런 걸 생각해 보자:
복잡한 weighted graph data structure가 있다. 이것의 개략적인 모양을 2차원 화면에 그리려 하는데, 모든 edge를 나타내기는 어려워서, weight만 다르고 시작점과 끝점이 같은 edge가 여러 개 있을 때 그들 중 하나만 그리기로 하였다. --> 한 번 그린 edge를 set에 넣고 두 번째부터 안 그리든지, 그릴 set을 처음에 만들고 시작하든지 알아서...

그럼에도 모르겠는 거: IEquatable에 왜 GetHashCode()가 포함되어 있지 않은가?




*또한 IEquatable에 없는 GetHashCode 멤버 함수가 IEqualityComparer에는 있다! -_-
그런데 IEqualityComparer를 구현해서 HashSet에서의 동일성 검증에 사용하려 하면, 그렇게 되지도 않는다. 우선 Equals의 원형부터
    public bool Equals(object objA, object objB)
로서, 마치 static 함수 같은 모양을 하고 있다(그러나 static은 아니다). C++/STL에서 operator overloading 하던 때의 짜증이 떠오른다... 이는 equality comparer라는 이름이 이미 암시하고 있기는 하다. 비교 대상이 아니라 '두 대상을 비교해 주는 무언가'라는 것.

# as는 이렇게 쓴다. 캐스트와 비슷하나, 변환이 실패했을 때 exception을 발생시키지 않고 그냥 null을 리턴한다.
class MyType {int m1; int m2;} // 모두 public 가정
public bool Equals(Object obj) {
    var p = obj as MyType; // 캐스트와 비슷
    if(p==null) return false;
    return m1==p.m1 && m2==p.m2; // custom equality test 예제
}

Sunday, May 12, 2013

이상하게 쓰레기값이 나오는데 구조체의 다음 변수가 찍힌다면...


Any CPU를 x64로 바꿔야지 뭐...


Padding 같은 게 있나 한참 찾아 봤는데 아니었고 그냥 저거였음 ㅇㅇ


IntPtr의 크기가 달라짐.

Thursday, May 9, 2013

Short-Circuit Evaluation

Lazy evaluation과는 다르다, Lazy evaluation과는!

Short-circuit evaluation

여러(n) 개의 msg 발생기가 있고, 
1) 그들 중 하나라도 발생하면 목적 프로그램(A)을 실행
2) 그들 중 모두가 발생해야 목적 프로그램(A)을 실행

하는 두 시나리오를 생각하자.

1)과 2) 모두 bool 값(B)에 따라 A의 실행 여부를 결정하되,

1)은 n-ary Or,
2)는 n-ary And
에 의해서 bool 값이 계산되는 것이다.

주의할 것은 사실 B값은 boolean 값이 아니라 enum {Undetermined, False, True} 값이라는 것.
그리고 B값을 계산하는 데 필요한 인수들도 그렇다는 것.

2)의 경우에는 그대로 두어도 문제가 없다.
n=3인 경우에 대해 생각하면, [U/U/U]가 [T/T/T]가 되면 A를 실행하고, 하나라도 F가 나타나는 순간 실행을 포기하면 된다. 그 외의 경우에는 무한 대기한다.

1)의 경우에는 short-circuit evaluation을 지원하지 않으면 문제가 된다.
마찬가지로 n=3에 대해 생각하면, [T/U/U]가 됐을 때 A를 실행하지 않고 U가 T 또는 F로 바뀔 때까지 무한 대기하는 것이다. 이것은 처음에 목적한 "하나라도 발생하면 A 실행"에 맞지 않는다.

이것저것 기능을 추가하다 보니,
C++(null pointer를 피하는 데 유용하다)와는 전혀 다른 이유로 short-circuit evaluation이 필요하게 되었다.

위키를 보니 재미있는 내용이 있는데, &&, ||는 short-circuit operator이지만 
bitwise operator인 &, |는 eager operator이다. (당연한가?)
Boolean operators in various languages
LanguageEager operatorsShort-circuit operatorsResult type
ABAPnoneandorBoolean1
AdaEiffelandorand thenor elseBoolean
ALGOL 68and, &, ∧ ; or, ∨andf , orf (both user defined)Boolean
C2none&&||?[1]Numeric (&&,||), opnd-dependent (?)
C++3&|&&||?[2]Boolean (&&,||), opnd-dependent (?)
GoOCamlHaskellnone&&||Boolean
C#Java, &|&&||Boolean



창 핸들을 만드는 동안 오류가 발생했습니다

System.ComponentModel.Win32Exception was unhandled   MyForm w = new MyForm IntPtr handle = wnd.Handle;   // Exception occurs here class MyFo...