Там какой-либо путь состоит в том, чтобы сделать что-то вроде этого в C#?
public void DoSomething(string parameterA, int parameterB)
{
}
var parameters = ("someValue", 5);
DoSomething(parameters);
Закрыть, но, к сожалению, только с использованием объекта (так что вы получите много упаковки / распаковки)
public void DoSomething(params object[] parameters)
{
}
var parameters = new object[]{"someValue", 5};
DoSomething(parameters); // this way works
DoSomething("someValue", 5); // so does this way
Если все они одного типа, да, вы можете сделать что-нибудь с этим эффектом:
public void Print(params string[] args) {
foreach (string arg in args) {
Console.WriteLine(arg);
}
}
// ...
Print("apple", "banana");
Print("apple", "banana", "cherry");
Print("apple", "banana", "cherry", "doughnut");
В противном случае, вы не можете развернуть параметры в таком месте без использования отражения. В C # нет эквивалента оператора splat в Ruby .
Не сегодня, нет. В настоящее время мы создаем прототип именно этой функции для возможной гипотетической будущей версии C #.
Если вы можете указать действительно замечательную причину, по которой вам нужна эта функция, это будет указывать на то, чтобы фактически вывести ее из прототипа и превратить в возможный гипотетический будущий выпуск. Какой у вас интересный сценарий, который мотивирует эту функцию?
(Помните, что предположения Эрика о возможных гипотетических будущих выпусках C # предназначены только для развлекательных целей и не должны толковаться как обещания, что такой выпуск когда-либо будет любой конкретный набор функций.)
Вы можете сделать это (.NET 4.0):
var parameters = Tuple.Create("someValue", 5);
DoSomething(parameters.Item1, parameter.Item2);
Как насчет этого в .NET 4 (ради любопытства)
public void DoSomething(string parameterA, int parameterB)
{
}
public void Helper(dynamic parameter)
{
DoSomething(parameter.Parameter1, parameter.Parameter2);
}
var parameters = new {Parameter1="lifeUniverseEverything", Parameter2=42};
Helper(parameters);
Вы можете вызвать его через отражение, но это повлечет за собой некоторые накладные расходы:
using System;
using System.Reflection;
namespace SO2744885
{
class Program
{
public void DoSomething(string parameterA, int parameterB)
{
Console.Out.WriteLine(parameterA + ": " + parameterB);
}
static void Main(string[] args)
{
var parameters = new object[] { "someValue", 5 };
Program p = new Program();
MethodInfo mi = typeof(Program).GetMethod("DoSomething");
mi.Invoke(p, parameters);
}
}
}
Конечно, если вы можете изменить сигнатуру метода так, чтобы он принимал массив, это тоже сработает, но в моем случае это будет выглядеть хуже. мнение.
Может быть этот способ более "чистый":
// standard method calling
DoSomething( "Johny", 5 );
// since C# 4.0 you can used "named parameters"
DoSomething( name: "Johny", number: 5 );
// calling with parameter's "container"
DoSomething( new DoSomethingParameters( "Johny", 5 ) );
// calling with parameter's "container"
DoSomething( new DoSomethingParameters{ Name = "Johny", Number = 5 } );
// calling with callback for parameters initialization
DoSomething( p => { p.Name = "Johny"; p.Number = 5; } );
// overload of DoSomething method with callback, which initialize parameters
public void DoSomething( Action<DoSomethingParameters> init ) {
var p = new DoSomethingParameters();
init( p );
DoSomething( p );
}
// overload of DoSomething method for calling with simple parameters
public void DoSomething( string name, int number ) {
var p = new DoSomethingParameters( name, number );
DoSomething( p );
}
// the "main executive" method which is "doing the work"
// all posible parameters are specified as members of DoSomethingParameters object
public void DoSomething( DoSomethingParameters p ) { /* ... */ }
// specify all parameters for DoSomething method
public class DoSomethingParameters {
public string Name;
public int Number;
public DoSomethingParameters() { }
public DoSomethingParameters( string name, int number ) {
this.Name = name;
this.Number = number;
}
}
Вдохновленный ответом Стивена:
static public void Execute<T1, T2>(this Tuple<T1, T2> parameters, Action<T1, T2> action)
{
action(parameters.Item1, parameters.Item2);
}
var parameters = Tuple.Create("someValue", 5);
parameters.Execute(DoSomething);
Мне нравится ответ Хенрика, за исключением того, что он навязывает несколько странный синтаксис: параметры вызывают метод сами на себя. Я бы сделал это наоборот. Единственная проблема с этим подходом в том, что он заставляет вас явно приводить метод к делегату.
В любом случае, вот основная идея:
// wrapped code to prevent horizontal overflow
public static void Execute<T1, T2>
(this Action<T1, T2> action, Tuple<T1, T2> parameters) {
action(parameters.Item1, parameters.Item2);
}
И так далее (для более T
s).
Использование:
var parameters = Tuple.Create("Hi", 10);
Action<string, int> action = DoSomething;
action.Execute(parameters);
Вы также можете легко сделать это с возвращаемым значением:
// wrapped code to prevent horizontal overflow
public static TResult Return<T1, T2, TResult>
(this Func<T1, T2, TResult> func, Tuple<T1, T2> parameters) {
return func(parameters.Item1, parameters.Item2);
}
И так далее.
Я также хотел бы отметить, что если вы не находитесь на .NET 4.0, это не значит, что вы не можете легко реализовать свой собственный тип Tuple
.
вы можете:
public void DoSomething(string parameterA, int parameterB)
{
}
var func = (Action)(() => DoSomething("someValue", 5));
func();
Если вы не хотите менять сигнатуру метода, почему бы не объявить новый метод с соответствующей сигнатурой и не использовать его в качестве прокси. Например
public void DoSomething(string parameterA, int parameterB)
{
// Original do Something
}
public void DoSomething(object[] parameters)
{
// some contract check whether the parameters array has actually a good signature
DoSomething(parameters[0] as string,(parameters[1] as int?).Value);
}
var parameters = new object[]{"someValue", 5};
DoSomething(parameters);
Вы также можете попробовать некоторые возможности LinFu.Reflection, такие как Late Binding. С его помощью вы можете сделать что-то вроде этого:
var dosomethingobject = new ObjectThatHasTheDoSomething();
DynamicObject dynamic = new DynamicObject(dosomethingobject);
var parameters = new object[]{"someValue", 5};
dynamic.Methods["DoSomething"](parameters);
Для этого вам нужно, чтобы метод DoSomething
находился внутри объекта.
«var» просто представляет определенный тип, это фактически сокращение для записи имени типа. Выше вы не указываете какой-либо тип. Единственный способ сделать это - создать класс параметров для массового представления входных данных ...
public void DoSomething(Parameters param)
{
...
}
var param = new Parameters("someValue", 5);
DoSomething(param);
... но это будет полезно только в определенных обстоятельствах. Вы можете создать несколько конструкторов Parameters для представления различных порядков параметров, но вызываемая функция будет принимать только ОДИН ввод - объект Parameters. Таким образом, вы действительно подрываете возможность перегрузки функции.
Короче говоря, нет. =)
Нет необходимости использовать отражение, если вы сначала храните как делегат, но это требует сильного объявления делегата.
public void DoSomething(string parameterA, int parameterB)
{
Console.WriteLine(parameterA+" : "+parameterB);
}
void Main()
{
var parameters = new object[]{"someValue", 5};
Action<string,int> func=DoSomething;
func.DynamicInvoke(parameters);
}
...и вы можете забыть о проверке типа/самостоятельности списка параметров во время компиляции. Вероятно, это плохо.