2011-04-08 8 views
7

クラスライブラリ内のオブジェクトに、メッセージの出力方法を気にせずにメッセージを出力する機能を提供したいと考えています。クラスライブラリは、コンソールアプリケーション、WinFormまたはWPFウィンドウアプリケーション、またはWebページで使用できます。何を使用しますか?デリゲート、イベント、またはFunc <T>?

私は元々、これを処理するために代理人を使うことに決めました。私はクラスを使用してこれを実装しましたが、コンパイラはデリゲートをこれらのオブジェクトのそれぞれが持つインターフェイスにデリゲートを入れようとしたときにデリゲートを気に入らなかった。

デリゲートをインターフェイスから外してコンパイルすることができたことがわかりましたが、これが実行しようとしていることがわかりません。また、クルージュのように思えますあなたのいずれかが...

インタフェースこれを達成するためのさまざまなアイデアを持っている場合:そこから

namespace Test 
{ 
    using System; 
    using System.Xml.Linq; 

    public interface IAction 
    { 
    DisplayMessageDelegate DisplayMessage(string message); 
    void Execute(); 
    XElement Serialize(XName elementName); 
    } 

    public delegate void DisplayMessageDelegate(string message); 
} 

を、私はこの動作を実装するかどうかはわかりません:(ところで、私はこのコードがないことを知っていますコンパイル...)

public class ActionClass1 : IAction 
{ 
    // Other methods not shown... 
    void Execute() 
    { 
    if (this.DisplayMessage != null) 
    { 
     this.DisplayMessage(“Hello”); 
    } 
    } 
} 

public class ConsoleClass 
{ 
    ActionClass1 class1 = new ActionClass1(); 
    class1.DisplayMessage = { x => Console.WriteLine(x); }; 
} 

public class WinFormClass 
{ 
    ActionClass1 class1 = new ActionClass1(); 
    Class1.DisplayMessage = {x => DisplayTextBox.Text = x; }; 
} 

答えて

11

Executeへの1回の応答に応答する複数のデリゲートを接続できるようにするには、間違いなくeventを使用します。 1つのアクションのみをフックする場合は、ActionまたはFuncデリゲートを使用します。

例では、Actionの代理人の1人が作業する必要があります。あなたの場合、代理人が文字列引数を取るので、Action<string>になります。 Actionは、0個以上の引数をとり、voidを返す単なるデリゲートです。あなたは何も返されていないように見えるので、私はActionを提案しています。

代理人が何かを返す必要がある場合にのみ、Func<TResult>を使用します。 FuncActionの違いは、Funcの代理人には戻り値の型があり、Actionの代理人には返されません。これらの代理人のいずれも、最大16個程度の引数を取ることができる汎用バージョンを持っています。

デリゲートに16個の以上の引数が必要な場合は、デザインを再考することをお勧めします:)

+1

params、ref/outなどよりも複雑なものが必要な場合は、言及する必要があります。Action/Funcは動作しません。また別の「きれいな」とは、パラメータに適切な名前を付けることです(インテリセンス)。それは私もアクションを使用すると言われています。 – Jake

1

あなたのインタフェース定義が間違っています。次のように指定する必要があります。

namespace Test 
{ 
    using System; 
    using System.Xml.Linq; 

    public interface IAction 
    { 
    DisplayMessageDelegate DisplayMessage { get; set; }; 
    void Execute(); 
    XElement Serialize(XName elementName); 
    } 

    public delegate void DisplayMessageDelegate(string message); 
} 

次に、インターフェイスを実装します。

4

Action<string>を使用してこれを行うことができます。

Func<T>は、引数をとらず、タイプTの単一の値を返すデリゲートを定義しているので、Func<T>は使用しません。Action<T>は、タイプTの単一の引数をとるデリゲートです。

私がしようと示唆している:

public interface IAction 
{ 
    Action<string> DisplayMessage { get; set; } 

    void Execute(); 
    XElement Serialize(XName elementName); 
} 

あなたは(完全に)このインタフェースを実装したら、あなたは経由でそれを使用することができます:

public class ConsoleClass 
{ 
    public void SomeMethod() 
    { 
     ActionClass1 class1 = new ActionClass1(); 
     class1.DisplayMessage = x => Console.WriteLine(x); 
    } 
} 

または:

あなたが行うことができ
public class ConsoleClass 
{ 
    public void SomeMethod() 
    { 
     ActionClass1 class1 = new ActionClass1(); 
     class1.DisplayMessage = this.Print; 
    } 

    private void Print(string message) 
    { 
     Console.WriteLine(message); 
    } 
} 

イベントで同じことが、私はこれに質問します。あなたのAPIは、あなたが応答しているイベントではなく、起こるべきアクションを記述しています。そのため、イベントはお勧めしません。

1

ここ

DisplayMessageDelegate DisplayMessage(string message); 

あなたは文字列を受け入れ、DisplayMessageDelegateを返すメソッドを記述します。 使用

event DisplayMessageDelegate DisplayMessage; 

代わりに。

0

個人的には、DisplayMessageという抽象メソッドを定義した抽象基本クラスを使用し、その基本クラスを継承してメッセージを表示する方法の動作を変更することをお勧めします。

+0

私はそれを考慮しました...これらの派生したクラスはForEachループで各アイテムのExecuteメソッドを実行するリストコレクションにあるという事実を(問題を単純化するために)取り除きました。その時点で実行しているアプリケーションのタイプに基づいて "DisplayMessage"をアップする... –

0

の代わりに:

DisplayMessageDelegate DisplayMessage(string message); 

の操作を行います。

event Action<string> DisplayMessage; 

その後、通常のあたりにDisplayMessageとを使用し、イベントは代理人です。

関連する問題