QA@IT

Objective-Cのdelegateと、C#のdelegateの違い

3670 PV

現在C#を勉強しています。

その中で、Objective-Cでいう所のdelegateの様な事を、C#でも行いたいと考えました。
しかし、C#のdelegateはObjective-Cの場合とは少し違うようです。

どうもC#のdelegateは特定の処理を変数みたいに扱える。Rubyでいうと、lambdaの様な機能を実現する物のように感じました(間違っていたらすいません)。

改めて質問なのですが、C#で、Objective-CのDelegateの様な処理を行いたい場合は、どのようにするのが良いのでしょうか?

回答

具体的にどのような事を実装できなくて困っているのかはわかりませんが、

C# のdelegateはご認識の通り関数ポインタ、関数をオブジェクトとして扱う、そんな機能です。
型推論やAction,Funcデリゲートが出てからは直接delegateキーワードを使う(delegateとタイプする)機会は減った気はしますがeventやlambda式を使う際によく使われます。

Objective-Cのdelegateはインターフェースや仮想関数の様な事を継承・実装などの制約なしに実現できる様なものだと思います、
これをC#で実現するには、正直いろいろあるとは思いますがdelegateを使った場合は以下の様になると思います。

class Program
{
    static void Main(string[] args)
    {
        var p = new Program();
        p.DoSomething();
        Console.ReadKey();
    }

    void DoSomething(){
        var s = new Sample();
        s.DelegateFunction = ConcreteFunction;
        s.DelegateProcedure = ConcreteProcedure;
        s.DoMain();
    }

    void ConcreteProcedure(){
        Console.WriteLine("ConcreteProcedure");
    }

    int ConcreteFunction(){
        Console.WriteLine("ConcreteFunction");
        return 0;
    }

}

public class Sample
{
    public Action DelegateProcedure;
    // 以下の2行と等価
    // public delegate void ProcedureDelegate();
    // public ProcedureDelegate DelegateProcedure;

    public Func<int> DelegateFunction;
    // 以下の2行と等価
    // public delegate int FunctionDelegate();
    // public FunctionDelegate DelegateFunction;

    public void DoMain(){
        if (DelegateProcedure != null) DelegateProcedure();
        if (DelegateFunction != null){
            var result = DelegateFunction();
        }
    }
}

上記はあくまで「このような事ができる」という例で、どのような事が実装できないかによって解決方法が異なって来ますのでその点は注意してください。

編集 履歴 (0)
  • いつもお返事ありがとうございます。たしかにやりたい事は書くべきでしたね、すいません。
    なるほど、Objective-cのdelegateと完全に同じ仕組みはないんですね。少しそのあたりを含めて、適切な実装を考えてみようと思います。ありがとうございました。
    -

いちおう、Objective-Cにdelegate機能はありません。
ただMacOSXやiOSが提供するAPIの一部に、delegateと呼ばれるprotocolが定義されているだけです。

delegate元のオブジェクトがdelegate先のメソッドを呼ぶだけなので、例えば以下のような実装になっています。

@class Hello;

// デリゲートの定義(デリゲート先)
@protocol HelloDelegate <NSObject>
@optional
- (NSString*)hello:(Hello*)hello greetingName:(NSString*)name;
@end

// デリゲートを利用するクラス(デリゲート元)
@interface Hello : NSObject
@property (nonatomic, weak, readwrite) id<HelloDelegate> delegate;
- (void)printGreeting:(NSString*)name;
@end

@implementation Hello

- (void)printGreeting:(NSString*)name
{
    // デリゲートのメソッドが実装されていれば利用する
    if ([_delegate respondsToSelector:@selector(hello:greetingName:)])
    {
        NSLog(@"%@", [_delegate hello:self greetingName:name]);
    }
    else
    {
        NSLog(@"Hello, %@", name);
    }
}

@end

delegate先のメソッドの実装を確認してから呼び出す仕組みなので、C#の場合はリフレクションAPIを使って実装してください。

編集 履歴 (0)
  • お返事ありがとうございます。リフレクションというのがあるんですね、勉強になりました。リフレクションをつかうか、明示的にメソッドを実装するかは、よく考えて見ようと思います。ありがとうございました。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。