I am looking for a way to chain several delegates so the result from one becomes the input of the next. I am trying to use this in equation solving program where portions are done by different methods. The idea is that when you are building the equation the program adds the delegates and chains them in a particular order, so it can be solved properly. If there is a better way to approach the problem please share.
问题:
回答1:
This might help:
public static Func<T1, TResult> Compose<T1, T2, TResult>(Func<T1, T2> innerFunc, Func<T2, TResult> outerFunc) {
return arg => outerFunc(innerFunc(arg));
}
This performs function composition, running innerFunc
and passing the result to outerFunc
when the initial argument is supplied:
Func<double, double> floor = Math.Floor;
Func<double, int> convertToInt = Convert.ToInt32;
Func<double, int> floorAndConvertToInt = Compose(floor, convertToInt);
int result = floorAndConvertToInt(5.62);
Func<double, int> floorThenConvertThenAddTen = Compose(floorAndConvertToInt, i => i + 10);
int result2 = floorThenConvertThenAddTen(64.142);
回答2:
Yes this is possible - you need to ensure that the return type of the delegate is one that is the parameter type of the delegate being invoked.
A lot of LINQ is built this ways, though you may want to take a look at expressions.
回答3:
The type of API you are describing is called a Fluent API. Take a look at the preceeding article for a good tutorial.
With regard to delegate chaining, take a look at the LINQ extension methods in .NET 3.5, in particular how lambda functions (delegates) passed to a function result in an IEnumerable result which can then be chained with another extension method + lambda.
In your specific case you might need to create a class called a Functor to accept a delegate and return another Functor which too can be operated on by delegates.
Best regards,
回答4:
using GetInvocationlist you can achieve this.
Delegate[] chain = chained.GetInvocationList();
int res = 10;
for( int i = 0; i < chain.Length; i++ )
{
//Call chain[i]
res = chain[i](res);
}
回答5:
I have been working on a similar problem myself which involved invoking a sequence of delegates and passing the output of one delegate to the next (and so on...) so thought you might be interested to see the code I developed as a proof-of-concept:
static class Program
{
private static IList<Func<int, int>> delegateList =
new List<Func<int, int>>()
{
AddOne, AddOne, AddOne, AddOne, AddOne,
AddOne, AddOne, AddOne, AddOne, AddOne,
};
static void Main(string[] args)
{
int number = 12;
Console.WriteLine("Starting number: {0}", number);
Console.WriteLine("Ending number: {0}",
delegateList.InvokeChainDelegates(number));
Console.ReadLine();
}
public static int AddOne(int num) { return num + 1; }
public static T InvokeChainDelegates<T>(this IEnumerable<Func<T, T>> source,
T startValue)
{
T result = startValue;
foreach (Func<T, T> function in source)
{
result = function(result);
}
return result;
}
}
The sequence has to contain delegates of the same type so is not as powerful as the already accepted answer but with a few tweaks, both bits of code could be combined to provide a powerful solution.