지난 포스트에 이어서...
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
Monday, May 27, 2013
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.
}
이거보단 훨씬 편하다.
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 예제
}
문제는 어느 인터페이스를 구현할 것인가이다. 구글에서 대충 검색하다 보면 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 예제
}
Tuesday, May 21, 2013
Sunday, May 12, 2013
Thursday, May 9, 2013
Short-Circuit 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이다. (당연한가?)
위키를 보니 재미있는 내용이 있는데, &&, ||는 short-circuit operator이지만
bitwise operator인 &, |는 eager operator이다. (당연한가?)
Language | Eager operators | Short-circuit operators | Result type |
---|---|---|---|
ABAP | none | and , or | Boolean1 |
Ada, Eiffel | and , or | and then , or else | Boolean |
ALGOL 68 | and, &, ∧ ; or, ∨ | andf , orf (both user defined) | Boolean |
C2 | none | && , || , ? [1] | Numeric (&& ,|| ), opnd-dependent (? ) |
C++3 | & , | | && , || , ? [2] | Boolean (&& ,|| ), opnd-dependent (? ) |
Go, OCaml, Haskell | none | && , || | Boolean |
C#, Java, | & , | | && , || | Boolean |
Subscribe to:
Posts (Atom)
창 핸들을 만드는 동안 오류가 발생했습니다
System.ComponentModel.Win32Exception was unhandled MyForm w = new MyForm IntPtr handle = wnd.Handle; // Exception occurs here class MyFo...
-
텍스트박스에서 엔터를 치면 자동으로 입력되게 하려고 keyup 이벤트 핸들러를 등록했다. 잘 동작하는 듯했는데 alert창을 닫아도 닫아도 계속 열리는 것이다. 크롬이어서 다행이지 IE였으면 무한히 열렸을 거야...스페이스바로 눌러보길 잘했...
-
진짜 되는 건 아니고 흉내낼 수는 있다. 새 창을 누르면 아무 것도 안 변한 것 같지만 PowerPoint 창 제목이 바뀌어 있다: 프레젠테이션1:2에서 :2 부분이 같은 파일을 연 창 여러 개 중 2번째라는 뜻이다('프레...
-
MathJax è Word MS Word 2007부터는 MathML을 문서에 바로 붙여넣을 수 있다. 이 블로그의 거의 대부분의 수식은 MathJax로 작성되어 있는데, 오른쪽 버튼 클릭하고 메뉴에서 MathML 또는 TeX 형식으로 ex...