replay a list of functions and parameters

2019-03-19 22:01发布

问题:

I have a series of functions that I want to have the following functionality.

  • When the function is called, add itself to a list of functions remembering the parameters and values
  • Allow the list of functions to be called at a later date

The different functions have a variety of different parameters and I'm struggling to think of an elegant way to do this. Any help would be appreciated.

回答1:

I think this would meet your needs, however the functions are not "adding themselves".

public class Recorder
{
    private IList<Action> _recording;
    public Recorder()
    {
        _recording = new List<Action>();
    }
    public void CallAndRecord(Action action)
    {
        _recording.Add(action);
        action();
    }
    public void Playback()
    {
        foreach(var action in _recording)
        {
            action();
        }
    }
}

//usage
var recorder = new Recorder();
//calls the functions the first time, and records the order, function, and args
recorder.CallAndRecord(()=>Foo(1,2,4));
recorder.CallAndRecord(()=>Bar(6));
recorder.CallAndRecord(()=>Foo2("hello"));
recorder.CallAndRecord(()=>Bar2(0,11,true));
//plays everything back
recorder.Playback();

One way to make the functions "add themselves" would be to use an AOP lib such as postsharp or linfu dynamic proxy, and add an interceptor which adds the function and args to the array. To do this would probably be more work than it would be worth IMO, as the above is much simpler and still achieves the desired functionality.



回答2:

There's hardly an elegant solution to this. Since you said the methods would all have different signature, there's no way to store them in a single array as delegates. With that out of the way, next you can try is using reflection, storing each parameter value in object[], storing the method as MethodInfo, and then invoking it.

Edit: This is what I could come up with:

    private Dictionary<MethodBase, object[]> methodCollection = new Dictionary<MethodBase, object[]>();

    public void AddMethod(MethodBase method, params object[] arguments)
    {
        methodCollection.Add(method, arguments);
    }

    private void MyMethod(int p1, string p2, bool p3)
    {
        AddMethod(System.Reflection.MethodInfo.GetCurrentMethod(), new object[] { p1, p2, p3 });
    }

    private void MyOtherMethod()
    {
        AddMethod(System.Reflection.MethodInfo.GetCurrentMethod(), new object[] { });
    }

Then just invoke with method.Invoke(method.ReflectedType, args)



回答3:

Maybe you could some how use the Delegate.DynamicInvoke(Object[] obj) function. You could add each method to an object array, then loop through the array calling DynamicInvoke on each one.



回答4:

I'm not sure I understand your question, but I think you could use array of pointers to a functions(in C# it is called delegates). So when function is called, put function pointer in a list. In this way you can call function from list. Here is some idea. Notice when you add new delegate pointer to a list (functionPointers), in second list myParameters you add new object of type Parameters which holds function parameters in public attribute called parameters. This means that delegate i in list functionPointers for parameters has i-th object in list myParameters. This is how you know which parameters, are for which function. Probably there are some betters solutions, but this is alternative.

delegate void NewDelegate();
class Parameter{
     public ArrayList parameters;

}
ArrayList functionPointers=new ArrayList();
ArrayList<Parameter> myParameters=new ArrayList<Parameter>();
NewDelegate myDelegate;

void someFunction(int a, int b){
   myDelegate+=someFunction;//you add this function to delegate because this function is called
   functionPointers.add(myDelegate);//Add delegete to list
   Parameter p=new Parameter();//Create new Parameter object
   p.parameters.add(a);//Add function parameters
   p.parameters.add(b);
   myParameters.add(p);//add object p to myParameters list

}



回答5:

You could consider using a list of actions or functions

using System;
using System.Collections.Generic;

namespace ReplayConsole
{
class Program
{
    private static IList<Action> _actions;

    static void Main(string[] args)
    {
        _actions = new List<Action>
                   {
                       () => {
                           //do thing 
                       },
                       () => {
                           //do thing 
                       },
                       () => {
                           //do thing 
                       },
                       () => {
                           //do thing 
                       },
                   };

        foreach (var action in _actions)
        {
            action();
        }
    }
}

if you want to store parameters as well and have you could use a Func and store and use it in much the same way

You could also look at Tasks

EDIT:

looking at the answers that popped up while I was writing mine this solution is very similar to Brook's