IT_Programming/C#

[C++/CLI, C#] Predicate으로 사용할 객체형 대리자 및 무명 메서드.

JJun ™ 2008. 1. 10. 11:15
* 주요 개념은 Passing parameters to predicates 컬럼에서..

List<>::Find() 등의 검색 메서드에서 조건을 지정할 때 사용하는 Predicate<> 타입의 대리자. MSDN에는 인수를 지정할 수 없는 static 함수형 예제만 나와 있는데, 이보다 더 많이 쓰이게 될 형식은 객체형 대리자 및 무명 메서드이다.

다음은 MSDN에 올라온 함수형 predicate 사용법의 예제다.
using System;
using System.Drawing;

public class Example
{
    public static void Main()
    {
        Point[] points = { new Point(100, 200),
            new Point(150, 250), new Point(250, 375),
            new Point(275, 395), new Point(295, 450) };

        
Point first = Array.Find(points, ProductGT10);

        Console.WriteLine("Found: X = {0}, Y = {1}", first.X, first.Y);
    }

    
private static bool ProductGT10(Point p)
    {
        return (p.X * p.Y > 100000);
    }

}

위 예제 predicate의 비교 구문 중 100000이란 조건을 임의의 수치로 바꾸고자 할 경우, 함수형 Predicate으론 외부 객체를 사용하지 않고서는 해결할 방법이 없다. 바로 이 때가 무명 메서드와 객체형 대리자가 등장할 좋은 시점이다.

다음은 무명 메서드를 이용한 방법이다.
...
int cond = 50000;
Point first = Array.Find(points,
        delegate(Point p) { return (p.X * p.Y > cond); });
...
해당 Predicate의 호출자 앞에 조건(int cond = 50000;)을 넣고 아예 Predicate으로 무명 메서드를 박는 방법으로서, 인수를 넘기는 방법을 제공함과 동시에 코딩 오버헤드를 크게 줄이고 있다.


다음은 객체형 Predicate을 이용한 방법이다(C#).
...
int cond = 50000;
Point first = Array.Find(points, (new IsBigger(cond)).Match);
...
...
class IsBigger
{
    int cond;
    public IsBigger(int cond) { this.cond = cond; }
    public Predicate<Point> Match { get { return IsMatch; } }
    bool IsMatch(Point p) { return (p.X * p.Y > this.cond); }
}
익명 메서드와 동일한 효과를 내지만 코딩 오버헤드가 크다는 것이 단점인데, 많이 쓰이게 될 경우에는 객체형 Predicate이 더 효율적이겠다. 하지만 C++/CLI에서는 익명 메서드를 지원하지 않으므로 객체형 Predicate 외에는 선택의 여지가 없다.


다음은 위 코드에 대한 C++/CLI 코드..
...
int cond = 50000;
Point first
    = Array::Find(points, (gcnew IsBigger(cond))->Match);
...
...
ref class IsBigger
{
    int cond_;
public:
    IsBigger(int cond) { cond_ = cond; }

    property Predicate<Point>^ Match
    {
        Predicate<Point>^ get()
        {
            return
            gcnew Predicate<Point>(this, &IsBigger::IsMatch);
        }
    }

private:
    bool IsMatch(Point p) { return (p.X * p.Y > cond_); }
};
C++/CLI에서는 함수에 대한 대리자 직접 변환을 지원 안하기 때문에 Predicate<>대리자를 직접 호출해야 한다는 점이 눈에 뜬다. C++/CLI의 특수성으로 인해 C#코드보다 지저분한 것이 사실이다.