Есть ли способ сделать что-то подобное в С#?

Есть ли способ сделать что-то подобное на С#?

public void DoSomething(string parameterA, int parameterB)
{

}

var parameters = ("someValue", 5);
DoSomething(parameters);

Ответ 1

Закрыть, но, к сожалению, использовать только объект (так что вы получаете много бокса/распаковки)

public void DoSomething(params object[] parameters)
{

}

var parameters = new object[]{"someValue", 5};
DoSomething(parameters); // this way works
DoSomething("someValue", 5); // so does this way

Ответ 2

Не сегодня, нет. Мы в настоящее время прототипируем именно эту функцию для возможной гипотетической будущей версии С#.

Если вы можете предоставить действительно удивительную причину, почему вы хотите эту функцию, это будет связано с тем, что она действительно выводит ее из прототипирования и в возможный гипотетический будущий выпуск. Какой ваш удивительный сценарий мотивирует эту функцию?

(Помните, что размышления Эрика о возможных гипотетических будущих выпусках С# предназначены только для развлекательных целей и не должны рассматриваться как promises, что когда-либо будет такой выпуск или что у него будет какой-либо конкретный набор функций.)

Ответ 3

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

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);

}

... и вы можете забыть о проверке типа/проверке типа компиляции в списке параметров. Возможно, это плохо.

Ответ 4

Вы можете вызвать его через отражение, но это навлечет некоторые издержки:

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);
        }
    }
}

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

Ответ 5

nope - это невозможно.

Ответ 6

Возможно, этот способ более "чист":

// 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;
    }
}

Ответ 7

Вдохновленный Стивеном:

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);

Ответ 8

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

Во всяком случае, здесь основная идея:

// 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, ...>.

Ответ 9

Вы можете сделать это (.NET 4.0):

var parameters = Tuple.Create("someValue", 5);

DoSomething(parameters.Item1, parameter.Item2);

Ответ 10

вы можете сделать:

public void DoSomething(string parameterA, int parameterB)
{

}

var func = (Action)(() => DoSomething("someValue", 5));
func();

Ответ 11

Если они все одинаковые, да, вы можете сделать что-то с этим:

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.

Ответ 12

Если вы не хотите изменять подпись метода, почему бы не объявить новый метод с соответствующей сигнатурой и использовать это как прокси. Как

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 находился внутри объекта.

Ответ 13

"var" просто представляет конкретный тип, он эффективно сокращает запись имени типа. В приведенном выше вы не указываете тип. Единственный способ сделать это - сделать класс параметров для представления вложенных массивов...

public void DoSomething(Parameters param)
{
...
}

var param = new Parameters("someValue", 5);
DoSomething(param);

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

Итак, короче говоря, нет. =)

Ответ 14

Как насчет этого в .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);