2010-04-10 2 views
0

У меня есть 3 функции. Их можно вызывать в любом порядке (позже они могут нуждаться в определенном порядке). Возвращаемое значение одной функции должно быть первым параметром следующего. Как мне это сделать? Я думаю, что это что-то вроде ниже. Каков наилучший способ сделать это?Функции вызова в цепочке событий/функций?

string void fn(string sz, data d, eventhdl nextFunc) 
{ 
    //do stuff 
    if(nextFunc == null) 
     return ret; 
    else 
     return nextFunc(ret, d, nextFunc.Next); 
} 
+1

То, что у вас есть, называется продолжением, и это не плохая идея. – erikkallen

ответ

1

Вам нужно несколько методов для участия в одном запросе. У меня есть вопрос. Я думаю, что у вас может быть собственный шаблон Decorator. Проблема в том, что это трудно сделать, но может быть Chain of Responsibility, если вы пытаетесь направьте запрос на правый функция.

2

Вы ищете что-то в этом роде?

T Foo<T>(T seed, IEnumerable<Func<T, T>> funcs) 
{ 
    T current = seed; 

    foreach (Func<T, T> func in funcs) 
    { 
     current = func(current); 
    } 

    return current; 
} 

Использование:.

int result = Foo<int>(1, new Func<int, int>[] 
      { 
       i => i + 1, 
       i => i * 2, 
       i => i * i 
      }); 

// result is 16 
1

Рассмотрим сделать класс ComboFunc текучим интерфейс на нем, так что вы можете сделать ...

вар п = новый ComboFunc() А ("arg1 ") .B (" арг2 ") С (." arg3"); var result = fn.Apply ("arg4");

Свободный интерфейс в классе ComboFunc можно использовать для создания внутренней функциональной цепочки, которую вы затем выполняете. B(), например, будет цепной функцией b() в цепочке Func внутри и возвращать новый объект ComboFunc().

Это дает вам (a) чистый синтаксис; (б) возможность задавать правила, которые ограничивают время разработки, какие функции можно назвать на вершине которой другие (вернув другой тип.

Что-то вроде ...

public abstract class ComboFuncBase 
    { 
     protected Func<string,string> chain = x => x;  // start with identity operation 

     // Here are your various functions ... defined as methods or as functions like this .. 
     protected Func<string, string> Afunc = input => input + "A"; 
     protected Func<string, string> Bfunc = input => input + "B"; 
     protected Func<string, string> Cfunc = input => input + "C"; 

     /// <summary> 
     /// Execute the chain of functions 
     /// </summary> 
     public string Apply(string argument) 
     { 
      return chain(argument); 
     } 

     /// <summary> 
     /// Apply FunctionC - always available 
     /// </summary> 
     public ComboFuncWithC C(string sz) 
     { 
      return new ComboFuncWithC() { chain = x => Cfunc(chain(x)) }; 
     } 

    } 

    /// <summary> 
    /// A chain without a C in it yet allows A's and B's 
    /// </summary> 
    public class ComboFunc : ComboFuncBase 
    { 
     /// <summary> 
     /// Apply FunctionA 
     /// </summary> 
     public ComboFunc A(string sz) 
     { 
      return new ComboFunc() { chain = x => Afunc(chain(x)) }; 
     } 

     /// <summary> 
     /// Apply FunctionB 
     /// </summary> 
     public ComboFunc B(string sz) 
     { 
      return new ComboFunc() { chain = x => Bfunc(chain(x)) }; 
     } 
    } 

    /// <summary> 
    /// After C has been applied you can't apply A or B 
    /// </summary> 
    public class ComboFuncWithC : ComboFuncBase 
    { 
    } 


    static void Main(string[] args) 
    { 
     string input = "hello"; 

     var combo = new ComboFunc().A(" world").B("!").C(" - see"); 

     // Intellisense/Compiler will not allow this ... 
     //var combo2 = new ComboFuncBase.ComboFunc().A(" world").C("!").B(" - see"); 
+0

Вам кажется, что вам нравится функциональное программирование (там вроде нет списка, все прикованное и т. Д.). Я не говорю ничего плохого, но это выглядит как его переоценка. Я не вижу никаких проблем, но делаю больше, чем это необходимо (ATM я использую param Type [] и цикл foreach. Дополнительная заметка: каждая функция является статической функцией. – 2010-04-10 19:04:14

+0

Функции Afunc, Bfunc, ... могут быть определены как статические методы, если вам нравится ... никаких других изменений не было. –

+0

Вы также можете создать список функций для вызова внутри класса, но в итоге вы вызываете одни и те же вложенные вызовы функций в конце, это меньше кода для создайте его, как вы идете.Этот подход также означает, что вы можете изменять типы параметров, поэтому Cfunc может взять int, Bfunc список, ... –

0
using System; 
using System.Collections.Generic; 

namespace FunctionCaller 
{ 
    class Demo 
    { 
     private class data { } 

     delegate string OperationDelegate(string sz, data d, Queue<OperationDelegate> funcs); 

     public void CallFunctions() 
     { 
      var funcs = new Queue<OperationDelegate>(); 
      funcs.Enqueue(fn1); 
      funcs.Enqueue(fn2); 
      funcs.Enqueue(fn3); 
      data d = new data(); 
      string sz = "Start"; 

      string result = CallFuncChain(sz, d, funcs); 

      Console.WriteLine(result); 
     } 

     private static string CallFuncChain(string sz, data d, Queue<OperationDelegate> funcs) 
     { 
      if (funcs.Count > 0) 
      { 
       OperationDelegate nextFunc = funcs.Dequeue(); 
       sz = nextFunc(sz, d, funcs); 
      } 
      return sz; 
     } 

     string fn1(string sz, data d, Queue<OperationDelegate> funcs) 
     { 
      string ret = sz + "\r\nfn1"; 
      ret = CallFuncChain(ret, d, funcs); 
      return ret; 
     } 

     string fn2(string sz, data d, Queue<OperationDelegate> funcs) 
     { 
      string ret = sz + "\r\nfn2"; 
      ret = CallFuncChain(ret, d, funcs); 
      return ret; 
     } 

     string fn3(string sz, data d, Queue<OperationDelegate> funcs) 
     { 
      string ret = sz + "\r\nfn3"; 
      ret = CallFuncChain(ret, d, funcs); 
      return ret; 
     } 
    } 
} 
+0

ваш код в основном реализация моего вопроса. Я надеялся, что кто-то скажет мне, Преданный CallFuncChain.Я думаю, что этого не существует.Я думаю, что я буду принимать этот ответ. – 2010-04-10 17:37:07

+0

Как это обеспечит порядок, в котором вы можете применять функции? –

+0

Можете ли вы использовать более OO-подход, например, посетитель p attern?Я знаю, что это не так, но вы можете создать дерево объектов, которое содержит один объект на одну функцию (по одному объекту за поведение), но может содержать другие объекты. Я был бы рад опубликовать образец, если это поможет. – goofballLogic

0

Хорошо, если вы не хотите использовать свой собственный CallFuncChain, есть альтернатива Linq.

using System; 
using System.Linq; 

namespace FunctionCaller 
{ 
    class Demo2 
    { 
     private class data { } 

     public void CallFunctions() 
     { 
      var funcs = new Func<string, data, string>[] { 
       fn1, fn2, fn3 
      }; 

      data d = new data(); 

      string sz1 = "Start"; 

      string result = funcs.Aggregate(
       sz1, 
       (sz, x) => x(sz, d) 
      ); 

      Console.WriteLine(result); 
     } 

     string fn1(string sz, data d) 
     { 
      return sz + "\r\nfn1"; 
     } 


     string fn2(string sz, data d) 
     { 
      return sz + "\r\nfn2"; 
     } 

     string fn3(string sz, data d) 
     { 
      return sz + "\r\nfn3"; 
     } 
    } 
} 

Я немного неловко об этом, хотя это чистое ... Linq позволяет нам сделать много вещей, с функциями, которые я иногда думаю «должны» быть сделано с объектами вместо этого.

Смежные вопросы