12

ある種のIExecutableインターフェースのデザインを作ろうとしています。詳細については説明しませんが、要点は、基本クラスから実行する必要のあるアクションがいくつかあるということです。それらは異なるパラメーターをとる場合があり(大したことではありません)、値を返す場合と返さない場合があります。

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

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を使用して行うことができると私に言いましたが、私は完全に同意しますが、アクションが値を返すかどうかを発信者が知ることができるように、それを1つのクラスにまとめる方法を見つけることができません。いいえ。

簡単な説明:次のようなことをしたい:

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

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

4 に答える 4

11

軽量のソリューションが必要な場合、最も簡単なオプションは2つの具象クラスを作成することです。1つはタイプのプロパティを含み、もう1つはタイプのプロパティを含みActionますFunc<T>

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

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

次に、次のように2つのタイプを作成できます。

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

プロパティを読み取り/書き込みにしたくない場合はAction、アクションデリゲートを引数としてコンストラクターに渡し、プロパティを読み取り専用にすることができます。

C#が関数とアクションを表すために2つの異なるデリゲートを必要とするという事実は、非常に厄介です。Unit人々が使用する回避策の1つは、 「戻り値なし」を表す型を定義し、の代わりにそれを使用することですvoid。その場合、タイプはちょうどで、の代わりにFunc<T>使用できます。タイプは次のようになります。Func<Unit>ActionUnit

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

値を作成するには、次のFunc<Unit>ように記述します。

Func<Unit> f = () => { /* ... */ return Unit.Value; }
于 2010-11-25T16:53:30.703 に答える
2

次のインターフェースでうまくいくはずです-本質的に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() { //... }
}
于 2010-11-25T18:01:22.603 に答える
0

メソッドの戻り値を無視できることをご存知ですか?使用する必要はありませ

于 2010-11-25T16:45:48.103 に答える
0

単純なものはどうですか?

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

    public object Execute(params object[] p)
    {
        return del.DynamicInvoke(p);
    }
}
于 2010-11-25T16:59:15.807 に答える