Как передать несколько методов (с параметрами) как параметр?

Предположим, что у меня есть следующий код WCF:

  try
  {
       ServiceClient proxy = new ServiceClient();
       proxy.ClientCredentials.UserName.UserName = "user";
       proxy.ClientCredentials.UserName.Password = "password";
       proxy.GetData(2);
       if (proxy.State = CommunicationState.Opened)
       {
           proxy.GetData("data");
       }
       proxy.Close();
  }
  catch (FaultException ex)
  {
      // handle the exception      
  }

И так как я заметил, что попытка... catch и другая логика повторяются, не говоря уже о том, что настройка вызова WCF дорого, я хочу отправить много "методов и параметров" этой функции.

По существу, передайте GetData(2) и GetData("data") как массив методов, и результаты возвращаются либо асинхронно, либо синхронно.

Как бы это сделать?

Я полагаю, что для обработки результатов [] и совместного доступа к результатам [] я мог бы использовать два объекта ref. Однако я не уверен, как передать "методы с параметрами" в качестве параметра для другой функции.

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

Может ли кто-нибудь подтолкнуть меня к правильному пути этого?

Дополнительная информация:

Я задаю этот вопрос поэтому я могу оптимизировать этот подход для обработки исключений и повторений WCF, но поэтому мне не нужно всегда открывать/закрывать клиента после каждого звоните.

Ответ 1

Используйте делегаты и передайте их в список.

Делегат С# Func<T> используется, когда требуется возвращаемое значение.

List<Func<Data>> funcList = new List<Func<Data>>();
funcList.Add( () => GetData(2) );

// You can use any condition as you otherwise would to add to the list.
if (proxy.State = CommunicationState.Opened)
{
   funcList.Add( () => GetData("data") );
}

List<Data> ProcessFuncs(List<Func<Data>> funcDatas)
{
    List<Data> returnList = new List<Data>();
    foreach(var func in funcDatas)
    {
        returnList.Add(func());
    }
}

(если типы возврата идентичны, это будет работать)

Это, конечно, пример; если ваши методы ничего не возвращают, вы можете использовать делегат С# Action, который просто выполняет действие и не возвращает никакого значения.

List<Action> actionList = new List<Action>();
actionList.Add( () => ProcessData("data")); // ProcessData is a void with no return type
actionList.Add( () => ProcessData(2));

public void ProcessActions(List<Action> actions)
{
    foreach(var action in actions)
    {
        action();
    }
}

В ответ на некоторые комментарии:

Этот код компилируется и эквивалентен:

class Program
{
    public static string GetData(string item) { return item; }
    public static string GetData(int item) { return item.ToString(); }

    static void Main(string[] args)
    {
        string someLocalVar = "what is it?";
        int someLocalValueType = 3;

        Func<string> test = () =>
        {
            return GetData(someLocalVar);
        };

        Func<string> test2 = () => GetData(someLocalValueType);
        someLocalValueType = 5;

        List<Func<string>> testList = new List<Func<string>>();

        testList.Add(() => GetData(someLocalVar));
        testList.Add(() => GetData(2));
        testList.Add(test);
        testList.Add(test2);

        someLocalVar = "something else";

        foreach(var func in testList)
        {
            Console.WriteLine(func());
        }

        Console.ReadKey();
    }
}

Результат:

enter image description here

Ответ 2

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

   List<Tuple<delegate, object[]>> delegates = new List<Tuple<delegate, object[]>>();

   delegates.Add(new Tuple<delegate, object[]>(new Func<Arg1Type, Arg2Type, ReturnType>(MyFunctionName), new object[] { arg1, arg2 });

   foreach (Tuple<delegate, object[]> d in delegates)
   {
        d.Item1.DynamicInvoke(d.Item2);
   }

Ответ 3

Я бы не использовал делегатов здесь, потому что тогда вы ограничены типами и решаете, что это становится ужасным и чрезмерно сложным. Я бы просто получил обратный вызов, который дает вам свободное владение над ServiceClient, как только он будет настроен. Я думаю, что это шаблон, который имеет имя, но я не знаю.

interface IProxyActionCallback
{
    void DoProxyStuff(ServiceClient proxy);
}

void MyMethod(IProxyActionCallback callback)
{
    try
    {
        ServiceClient proxy = new ServiceClient();
        proxy.ClientCredentials.UserName.UserName = "user";
        proxy.ClientCredentials.UserName.Password = "password";

        callback.DoProxyStuff(proxy);

        proxy.Close();
    }
    catch (FaultException ex)
    {
        // handle the exception      
    }
}

Затем вы вызываете метод следующим образом:

MyMethod(new DoSpecificStuff());

Где DoSpecificStuff - это класс, который реализует интерфейс и позволяет вам выполнять определенные вызовы с помощью прокси:

class DoSpecificStuff : IProxyActionCallback
{
    public void DoProxyStuff(ServiceClient proxy)
    {
        proxy.GetData(2);
        if (proxy.State = CommunicationState.Opened)
        {
            proxy.GetData("data");
        }
    }
}

Итак, у вас будет множество классов, которые реализуют интерфейс, и все они "разделяют" один и тот же файл прокси-сервера с пробкой, который находится в одном месте.

Ответ 4

Вы можете использовать делегаты С#:

Делегат - это тип, который представляет ссылки на методы с конкретный список параметров и тип возвращаемого значения. Когда вы создаете экземпляр делегата, вы можете связать свой экземпляр любым способом с помощью совместимый тип подписи и возврата. Вы можете вызвать (или вызвать) метод через экземпляр делегата. Делегаты используются для прохождения методы как аргументы другим методам. Обработчики событий не более чем методы, которые вызываются через делегатов. Вы создаете пользовательский метод и класс, такие как элемент управления Windows, могут вызывать ваш метод когда происходит определенное событие. В следующем примере показан делегат Объявление:

Подробнее об этом: http://msdn.microsoft.com/en-us/library/ms173171.aspx

Ответ 5

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

public void strategy<R, T1, T2>(Func<R, T1, T2> f);

public bool predicate(string a, string b);

strategy<bool, string, string>(predicate);

Первая строка объявляет функцию strategy() прием функции f; Эта функция возвращает тип R и принимает два параметра типа T1 и T2.

Вторая строка определяет функцию, которая возвращает bool и принимает два string.

Третья строка вызывает стратегию, передающую ей предикат в качестве параметра.

Ответ 6

Не уверен, что вы понимаете, чего вы пытаетесь достичь, но в основном, если ваша служба предоставляет метод GetData(int) и метод GetData(string), а также прокси-сервер async, вы должны вызывать оба асинхронно, используя что-то вроде:

var getData = proxy.GetDataAsync(2);
var getData2 = proxy.GetDataAsync("data");

await Task.WhenAll(getData, getData2);

// Gets the result using getData.Result...etc.