2011-12-21 32 views
8

Tengo una serie de funciones que quiero que tengan la siguiente funcionalidad.reproducir una lista de funciones y parámetros

  • Cuando se invoca la función, sumarse a una lista de funciones para recordar los parámetros y valores
  • Permitir la lista de funciones que se llamará en una fecha posterior

Las diferentes funciones tienen una variedad de parámetros diferentes y estoy luchando para pensar en una manera elegante de hacer esto. Cualquier ayuda sería apreciada.

+0

¿Todas estas funciones tendrán las mismas firmas o serán diferentes? ¿Recordará estas funciones con los mismos argumentos o cambiarán? –

+0

@JeffMercado Serán diferentes con una cantidad variable de parámetros y tipos de devolución. –

+2

Tal vez eche un vistazo a esta pregunta. http://stackoverflow.com/questions/377217/c-sharp-delegate-for-two-methods-with-different-parameters Puede que no sea exactamente lo mismo que intenta hacer, pero se trata de ejecutar delegados con diferentes parámetros –

Respuesta

9

Creo que esto sería satisfacer sus necesidades, sin embargo, las funciones no están "añadiendo a sí mismos".

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(); 

Una manera de hacer las funciones de "sumarse" sería el uso de un AOP lib como PostSharp o Linfu proxy dinámico, y añadir un interceptor que añade la función y args a la matriz. Hacer esto probablemente sería más trabajo de lo que valdría la IMO, ya que lo anterior es mucho más simple y aún así se logra la funcionalidad deseada.

+0

¡Bien hecho, este es el mejor! – MrD

+0

De hecho, excelente solución. –

+0

Muy buena respuesta. +1 –

1

No estoy seguro de entender su pregunta, pero creo que podría usar un conjunto de punteros a una función (en C# se llama delegados). Entonces, cuando se llama a la función, coloca el puntero de función en una lista. De esta forma puede llamar a la función de la lista. Aquí hay una idea. Observe que cuando agrega un nuevo puntero delegado a una lista (functionPointers), en la segunda lista myParameters agrega un nuevo objeto de tipo Parameters que contiene los parámetros de función en el atributo público llamado parameters. Esto significa que delegue i en la lista functionPointers para los parámetros tiene i -ésimo objeto en la lista myParameters. Así es como usted sabe qué parámetros, para qué función. Probablemente haya algunas soluciones mejores, pero esta es una alternativa.

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 

}

+0

Este código ni siquiera se compila. No puede almacenar ningún método en un delegado sin parámetros. Debes seguir las reglas de firma del método. –

3

tal vez usted podría utilizar alguna forma la función Delegate.DynamicInvoke(Object[] obj). Puede agregar cada método a una matriz de objetos, luego recorrer la matriz llamando a DynamicInvoke en cada uno.

5

No hay una solución elegante para esto. Como dijo que todos los métodos tendrían una firma diferente, no hay forma de almacenarlos en una única matriz como delegados. Con eso fuera del camino, lo próximo que puede intentar es usar la reflexión, almacenar cada valor del parámetro en el objeto [], almacenar el método como MethodInfo y luego invocarlo.

Editar: Esto es lo que podría llegar a:

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[] { }); 
    } 

A continuación, sólo invocar con method.Invoke(method.ReflectedType, args)

+0

+1 Esto es más de lo que estaba tratando de decir ... pero hágalo con DynamicInvoke. Nunca lo había usado antes, así que podría estar fuera de la base. –

+0

Para usar DynamicInvoke necesita la instancia de delegado para la que necesita un Tipo e información de método para que pueda crear un delegado con 'Delegate.CreateDelegate()', que es básicamente lo mismo, solo unos pocos pasos más. Aún necesitas reflexión. –

1

Se podría considerar el uso de una lista de acciones o funciones

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(); 
     } 
    } 
} 

si desea almacenar parámetros así y tienen que podría utilizar un Func y almacenar y utilizar en la misma forma

también podría mirar a Tasks

EDIT:

mirando las respuestas que apareció mientras estaba escribiendo esta mina de SOLUTIO n es muy similar a Brook's

Cuestiones relacionadas