Переменные параметры в С# Lambda
Возможно ли иметь С# лямбда/делегат, который может принимать переменное количество параметров, которые могут быть вызваны с помощью динамического вызова?
Все мои попытки использовать ключевое слово '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"}});
}
Ответы
Ответ 1
Причина, по которой это не работает при передаче аргументов непосредственно в DynamicInvoke()
, состоит в том, что DynamicInvoke()
ожидает массив объектов, один элемент для каждого параметра целевого метода, а компилятор будет интерпретировать один массив как массив params до DynamicInvoke()
вместо одного аргумента целевому методу (если вы не сделаете его как одиночный object
).
Вы также можете вызвать DynamicInvoke()
, передав массив, содержащий массив параметров целевого метода. Внешний массив будет принят в качестве аргумента для параметра DynamicInvoke()
single params, а внутренний массив будет принят как массив 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"
}
Ответ 2
Нет, но любой из параметров, которые он принимает, может быть массивом.
Без подробностей, что длинный и короткий.
Ответ 3
Нет, но с небольшой помощью вы можете почти подделать его:
object[] Params(params object[] args) { return args;}
// :
Action<string, object[]> CWL =
(format, args) => Console.WriteLine(format, args);
CWL("{0}, {1}", Params(1,2));
Ответ 4
Добавляя к ответу Mark, я бы создал метод расширения для очистки бит:
static DynamicInvokeParams(this ParamsDelegate delegate, params object[] args)
{
delegate.DynamicInvoke(new [] {args});
}
И тогда вам просто нужно сказать:
paramsDelegate.DyanamicInvokeParams(1, 2, 3);
Ответ 5
Я чувствую, что здесь очень важный момент, который здесь не обсуждается, и что , если вы определили тип делегата, который принимает аргумент params
, очень мало смысла вызывать DynamicInvoke
на нем вообще. Единственный сценарий, который я могу себе представить, в котором это вступает в игру, - это если у вас есть делегат вашего пользовательского типа, и вы передаете его как параметр для некоторого метода, который принимает аргумент Delegate
и вызывает DynamicInvoke
.
Но посмотрим на этот код в обновлении OP:
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");