2010-11-25 16 views
9

私はある種のIExecutableインターフェイスのデザインを作ろうとしています。詳細はわかりませんが、基本クラスから実行する必要があるアクションがいくつかあります。彼らは異なるパラメータを取るかもしれません(大したことはありません)、値を返すかもしれません。カプセル化アクション<T>およびFunc <T>?

これまでのところ、これは私のデザインです:

public abstract class ActionBase 
{ 
    // ... snip ... 
} 

public abstract class ActionWithResultBase<T>: ActionBase 
{ 
    public abstract T Execute(); 
} 

public abstract class ActionWithoutResultBase: ActionBase 
{ 
    public abstract void Execute(); 
} 

これまでのところ、私の具体的な行動のそれぞれは、ActionWithResultBaseまたはActionWithoutResultの塩基のいずれかからの子にする必要がありますが、私は本当に好きではありません。 Executeの定義をActionBaseに移すことができれば、具体的なクラスが値を返すかどうかを考えれば、私は目標を達成することができます。

誰かが、これはFuncとActionを使って行うことができますが、私は完全に同意していますが、呼び出し元がアクションが実行されているかどうかを知るために、値を返すかどうかを指定します。

概要:あなたは、メソッド、右の戻り値を無視することができることを知っている

// Action1.Execute() returns something. 
var a = new Action1(); 
var result = a.Execute(); 

// Action2.Execute() returns nothing. 
var b = new Action2(); 
b.Execute(); 
+0

私の目標は、抽象的なExecute in ActionBaseを持ち、ActionWithResultBaseとActionWithoutResultBaseを作成しないことです。 – Alpha

答えて

6

軽量ソリューションが必要な場合は、最も簡単なオプションは2つの具体的なクラスを記述することです。あなたがActionをしたくない場合は

var a1 = new ActionWithResult<int> { 
    CanExecute = true, 
    Action =() => { 
    Console.WriteLine("hello!"); 
    return 10; 
    } 
} 

:次に、あなたがこのような2種類を構築することができます

public class ActionWithResult<T> : ActionBase { 
    public Func<T> Action { get; set; } 
} 

public class ActionWithoutResult : ActionBase { 
    public Action Action { get; set; } 
} 

:一つは、タイプActionとタイプFunc<T>の他のプロパティのプロパティが含まれていますプロパティを読み書きする場合は、コンストラクタへのアクションデリゲートを引数として渡して、プロパティを読み取り専用にすることができます。

C#には、関数とアクションを表すために2つの異なる代理人が必要であるということは非常に面倒です。人々が使用する回避策の1つは、「戻り値なし」を表すタイプUnitを定義し、voidの代わりに使用することです。あなたのタイプはFunc<T>になり、Actionの代わりにFunc<Unit>を使用することができます。次のインタフェースが何をすべき

public class ActionExecuter 
{ 
    private MulticastDelegate del; 
    public ActionExecuter(MulticastDelegate del) 
    { 
     this.del = del; 
    } 

    public object Execute(params object[] p) 
    { 
     return del.DynamicInvoke(p); 
    } 
} 
+0

ありがとうございます。私はあなたの答えをマークする前に私が待っていたのを知っていますが、誰かが解決策を思いついたかどうかを本当に見たいと思っていました。あなたのアプローチが問題をかなり解決していない場合でも、それは確かに良い答えであり、この問題を克服するための良い、良い回避策を示しています。 – Alpha

0

:私のような何かをしたいですか? にはがありません。

+0

はい、あなたはその通りですが、それは設計上何かがあるとは思いません。また、誰かが、私は、操作が成功したことを示しているだけのノーリターンのためにいつもブールを返すように勧めましたが、それは正しいとは思えません。操作で値が返されない場合は、なぜそれを強制しますか? – Alpha

+0

@Alpha - 操作が自然に何かを返さなければ、それはしてはならないと私は同意します。例外的に "false"を返すべきではないので、 "true"を返すことは正しくありません。しかし、私はまだあなたの設計目標を理解していません。あなたの目的は構文的な砂糖に基づいているようですが、私はあなたが達成しようとしていることが分かりません。私は彼らに何が問題なのかを説明する必要があると思いますか? – annakata

0

:あなたが書くつもりFunc<Unit>値を作成するには

public class Unit { 
    public static Unit Value { get { return null; } } 
} 

Unitタイプは、このようになります。トリック - それは基本的にNullableパターンをコピーしています

public interface IActionBase 
{ 
     bool HasResult { get; } 
     void Execute() { } 
     object Result { get; } 
} 

public interface IActionBase<T> : IActionBase 
{ 
     new T Result { get; } 
} 

public sealed class ActionWithReturnValue<T> : IActionBase<T> 
{ 
     public ActionWithReturnValue(Func<T> action) { _action = action; } 
     private Func<T> _action; 

     public bool HasResult { get; private set; } 
     object IActionBase.Result { get { return this.Result; } } 
     public T Result { get; private set; } 
     public void Execute() 
     { 
      HasResult = false; 
      Result = default(T); 
      try 
      { 
       Result = _action(); 
       HasResult = true; 
      } 
      catch 
      { 
       HasResult = false; 
       Result = default(T); 
      } 
     } 

} 

public sealed class ActionWithoutReturnValue : IActionBase 
{ 
     public bool HasResult { get { return false; } } 
     object IActionBase.Result { get { return null; } } 
     public void Execute() { //... } 
} 
+0

また、同様のことについて考えましたが、私の問題はコンパイル時にどの型が返されるかわからないことです。私はいつもActionExecuter を作ってExecute return Tを作ることができましたが、何かを返す必要はありませんでした。 – Alpha

1

:簡単な何かについて何

Func<Unit> f =() => { /* ... */ return Unit.Value; } 
関連する問題