Переменные параметры в C # Lambda - PullRequest
13 голосов
/ 27 августа 2010

Возможно ли иметь лямбда / делегат C #, который может принимать переменное число параметров, которые могут быть вызваны с помощью динамического вызова?

Все мои попытки использовать ключевое слово 'params' в этом контексте потерпели неудачу.


ОБНОВЛЕНИЕ С РАБОЧИМ КОДОМ ОТ ОТВЕТ :

delegate void Foo(params string[] strings);

static void Main(string[] args)                       
{
    Foo x = strings =>
    {
        foreach(string s in strings)
            Console.WriteLine(s);
    };

    //Added to make it clear how this eventually is used :)
    Delegate d = x;

    d.DynamicInvoke(new[]{new string[]{"1", "2", "3"}});
}

Ответы [ 5 ]

15 голосов
/ 27 августа 2010

Причина, по которой он не работает при передаче аргументов непосредственно DynamicInvoke(), заключается в том, что DynamicInvoke() ожидает массив объектов, один элемент для каждого параметра целевого метода, и компилятор будет интерпретировать один массив какмассив params в DynamicInvoke() вместо одного аргумента для целевого метода (если только вы не приведете его как один object).

Вы также можете вызвать DynamicInvoke(), передав массив, содержащий массив параметров целевого метода.Внешний массив будет принят в качестве аргумента для единственного параметра параметра DynamicInvoke(), а внутренний массив будет принят как массив params для целевого метода.

delegate void ParamsDelegate(params object[] args);

static void Main()
{  
   ParamsDelegate paramsDelegate = x => Console.WriteLine(x.Length);

   paramsDelegate(1,2,3); //output: "3"
   paramsDelegate();      //output: "0"

   paramsDelegate.DynamicInvoke((object) new object[]{1,2,3}); //output: "3"
   paramsDelegate.DynamicInvoke((object) new object[]{}); //output: "0"

   paramsDelegate.DynamicInvoke(new []{new object[]{1,2,3}}); //output: "3"
   paramsDelegate.DynamicInvoke(new []{new object[]{}});      //output: "0"
}
1 голос
/ 27 августа 2010

Нет, но любой из параметров, которые он принимает, может быть массивом.

Без подробностей, это длинный и короткий вопрос.

0 голосов
/ 27 августа 2010

Мне кажется, что есть очень важный момент, который здесь не обсуждается, и это то, что , если вы определили тип делегата, который принимает аргумент params, очень мало смысла вызывать DynamicInvoke на это вообще . Сценарий only , который я могу себе представить, заключается в том, что если у вас есть делегат пользовательского типа и вы передаете его в качестве параметра какому-либо методу, который принимает аргумент Delegate и вызывает DynamicInvoke на , что .

Но давайте посмотрим на этот код в обновлении ОП:

delegate void Foo(params string[] strings);

static void Main(string[] args)                       
{
    Foo x = strings =>
    {
        foreach(string s in strings)
            Console.WriteLine(s);
    };

    x.DynamicInvoke(new[]{new string[]{"1", "2", "3"}});
}

Вызов DynamicInvoke, приведенный выше, совершенно лишний. Для последней строки было бы гораздо разумнее прочитать:

x("1", "2", "3");
0 голосов
/ 27 августа 2010

Добавляя к ответу Марка, я бы создал метод расширения, чтобы немного убрать:

static DynamicInvokeParams(this ParamsDelegate delegate, params object[] args)
{
  delegate.DynamicInvoke(new [] {args});
}

И тогда вам просто нужно сказать:

paramsDelegate.DyanamicInvokeParams(1, 2, 3);
0 голосов
/ 27 августа 2010

Нет, но с небольшой помощью вы можете почти подделать его:

object[] Params(params object[] args) { return args;}

// :

Action<string, object[]> CWL = 
                  (format,  args) => Console.WriteLine(format, args);

CWL("{0}, {1}", Params(1,2));
...