Call functions in an event/function chain?
I have 3 functions. They can be called in any order (later they may need specific order). The return value of one function should be the first param of the next. How do i do this? what i am thinking is something like the below. Whats the best way to do this?
string void fn(string sz, data d, eventhdl nextFunc)
{
//do stuff
if(nextFunc == nul开发者_高级运维l)
return ret;
else
return nextFunc(ret, d, nextFunc.Next);
}
Are you looking for something like this?
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;
}
Usage:
int result = Foo<int>(1, new Func<int, int>[]
{
i => i + 1,
i => i * 2,
i => i * i
});
// result is 16
You need multiple methods to participate in a single request. Order matters. I think you might have yourself a Decorator pattern in your problem. It's hard to tell working backward from implementation, though. It might be a Chain of Responsibility if you are trying to route a request to the right function.
Consider making a class ComboFunc
with a fluent interface on it so you can do ...
var fn = new ComboFunc().A("arg1").B("arg2").C("arg3"); var result = fn.Apply("arg4");
The fluent interface on class ComboFunc can be used to build up the function chain internally which you then execute. B() for example would chain function b() onto the Func chain internally and return a new ComboFunc() object.
This gives you (a) clean syntax; (b) the ability to specify rules that constrain AT DESIGN TIME which functions can be called on top of which others (by returning a different type.
Something like ...
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");
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;
}
}
}
Ok, if you don't want to use your own CallFuncChain, there is an alternative using 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";
}
}
}
I'm a bit uneasy about this, although it's clean... Linq lets us do many things with functions which I sometimes think "should" be done with objects instead.
精彩评论