Есть ли способ сделать что-то подобное на С#?
public void DoSomething(string parameterA, int parameterB)
{
}
var parameters = ("someValue", 5);
DoSomething(parameters);
Есть ли способ сделать что-то подобное на С#?
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
Не сегодня, нет. Мы в настоящее время прототипируем именно эту функцию для возможной гипотетической будущей версии С#.
Если вы можете предоставить действительно удивительную причину, почему вы хотите эту функцию, это будет связано с тем, что она действительно выводит ее из прототипирования и в возможный гипотетический будущий выпуск. Какой ваш удивительный сценарий мотивирует эту функцию?
(Помните, что размышления Эрика о возможных гипотетических будущих выпусках С# предназначены только для развлекательных целей и не должны рассматриваться как promises, что когда-либо будет такой выпуск или что у него будет какой-либо конкретный набор функций.)
Не нужно использовать отражение, если вы сначала сохраняете его как делегата, но для этого требуется сильное объявление делегата.
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);
}
... и вы можете забыть о проверке типа/проверке типа компиляции в списке параметров. Возможно, это плохо.
Вы можете вызвать его через отражение, но это навлечет некоторые издержки:
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);
}
}
}
Конечно, если вы можете изменить подпись метода для принятия массива, это тоже сработает, но это будет выглядеть хуже, на мой взгляд.
nope - это невозможно.
Возможно, этот способ более "чист":
// standard method calling
DoSomething( "Johny", 5 );
// since C# 4.0 you can used "named parameters"
DoSomething( name: "Johny", number: 5 );
// calling with parameter "container"
DoSomething( new DoSomethingParameters( "Johny", 5 ) );
// calling with parameter "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<T1, T2, ...>
.
Вы можете сделать это (.NET 4.0):
var parameters = Tuple.Create("someValue", 5);
DoSomething(parameters.Item1, parameter.Item2);
вы можете сделать:
public void DoSomething(string parameterA, int parameterB)
{
}
var func = (Action)(() => DoSomething("someValue", 5));
func();
Если они все одинаковые, да, вы можете сделать что-то с этим:
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");
В противном случае нет, вы не можете расширять параметры на месте, не используя отражение. С# не имеет эквивалента Ruby оператор splat.
Если вы не хотите изменять подпись метода, почему бы не объявить новый метод с соответствующей сигнатурой и использовать это как прокси. Как
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. Таким образом, вы действительно подрываете способность перегружать функцию.
Итак, короче говоря, нет. =)
Как насчет этого в .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);