воспроизвести список функций и параметров - PullRequest
8 голосов
/ 21 декабря 2011

У меня есть ряд функций, которые я хочу иметь следующие функции.

  • Когда функция вызывается, добавьте себя в список функций, запоминая параметры и значения
  • Разрешить вызывать список функций позднее

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

Ответы [ 5 ]

9 голосов
/ 21 декабря 2011

Я думаю, что это будет соответствовать вашим потребностям, однако функции не "добавить себя".

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

Один из способов «добавить себя» - это использовать библиотеку AOP, такую ​​как динамический прокси postharp или linfu, и добавить перехватчик, который добавляет функцию и аргументы в массив. Для этого, вероятно, потребовалось бы больше работы, чем стоило бы ИМО, поскольку вышеприведенное намного проще и все же обеспечивает желаемую функциональность.

5 голосов
/ 21 декабря 2011

Едва ли это элегантное решение.Поскольку вы сказали, что все методы будут иметь разную сигнатуру, нет способа сохранить их в одном массиве в качестве делегатов .После этого вы можете попробовать использовать отражение, сохраняя каждое значение параметра в object [], сохраняя метод как MethodInfo, а затем вызывая его.

Редактировать: это то, что я мог бы придуматьс помощью:

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

Затем просто вызовите с помощью method.Invoke(method.ReflectedType, args)

3 голосов
/ 21 декабря 2011

Может быть, вы могли бы как-нибудь использовать функцию Delegate.DynamicInvoke(Object[] obj). Вы можете добавить каждый метод в массив объектов, а затем перебрать массив, вызывая DynamicInvoke для каждого из них.

1 голос
/ 21 декабря 2011

Вы могли бы рассмотреть возможность использования списка действий или функций

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

, если вы также хотите сохранить параметры и можете использовать Func и сохранять и использовать его почти таким же образом

Вы также можете посмотреть на Задачи

РЕДАКТИРОВАТЬ:

, глядя на ответы, которые появились, когда я писал свои, это решение очень похоже на * 1012 Брука*

1 голос
/ 21 декабря 2011

Я не уверен, что понимаю ваш вопрос, но я думаю, что вы могли бы использовать массив указателей на функции (в C # это называется делегатами).Поэтому, когда вызывается функция, поместите указатель на функцию в список.Таким образом, вы можете вызвать функцию из списка.Вот некоторая идея.Обратите внимание, когда вы добавляете новый указатель делегата в список (functionPointers), во второй список myParameters вы добавляете новый объект типа Parameters, который содержит параметры функции в открытом атрибуте с именем parameters.Это означает, что делегат i в списке functionPointers для параметров имеет i -й объект в списке myParameters.Так вы узнаете, какие параметры предназначены для какой функции.Возможно, есть некоторые решения, которые лучше, но это альтернатива.

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

}

...