有没有办法在C#中做这样的事情?

时间:2010-04-30 13:40:34

标签: c# parameters

有没有办法在C#中做这样的事情?

public void DoSomething(string parameterA, int parameterB)
{

}

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

14 个答案:

答案 0 :(得分:21)

关闭,但不幸地只使用对象(所以你得到很多拳击/拆箱)

public void DoSomething(params object[] parameters)
{

}

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

答案 1 :(得分:14)

不是今天,不是。我们目前正在为可能的假设未来版本的C#进行原型设计。

如果你能提供一个真正令人敬畏的理由,为什么你想要这个功能,这将是实际上从原型开始到可能的假设未来版本。什么是你激发这个功能的令人敬畏的场景?

(请记住,Eric对C#可能假设的未来版本的猜测仅用于娱乐目的,不应被解释为承诺将会有这样的版本,或者它将具有任何特定的功能集。)

答案 2 :(得分:10)

如果您第一次存储为委托,则无需使用反射,但它确实需要强大的委托声明。

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

}

...你可以忘记参数列表的编译时类型/健全性检查。可能是一件坏事。

答案 3 :(得分:8)

你可以通过反射来调用它,但这会产生一些开销:

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

当然,如果您可以更改方法签名以获取数组,那么它也会起作用,但在我看来这看起来会更糟。

答案 4 :(得分:4)

nope - 这是不可能的。

答案 5 :(得分:3)

也许这种方式更“干净”:

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

答案 6 :(得分:3)

受史蒂文的回答启发:

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

答案 7 :(得分:3)

我喜欢Henrik的答案,除了它强加了一些奇怪的语法:参数调用自己的方法。我会反过来这样做。这种方法的唯一问题是它使您明确地将方法强制转换为委托。

无论如何,这是基本的想法:

// 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, ...>类型。

答案 8 :(得分:2)

您可以这样做(.NET 4.0):

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

DoSomething(parameters.Item1, parameter.Item2);

答案 9 :(得分:2)

你可以这样做:

public void DoSomething(string parameterA, int parameterB)
{

}

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

答案 10 :(得分:1)

如果它们都是相同的类型,是的,你可以做一些这样的事情:

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#没有相当于Ruby的 splat operator

答案 11 :(得分:1)

如果您不想更改方法签名,为什么不使用适当的签名声明新方法并将其用作代理。像

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方法在对象内。

答案 12 :(得分:0)

“var”只表示特定类型,它是写入类型名称的有效简写。在上面你没有指定任何类型。唯一的方法是创建一个参数类来批量表示输入...

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

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

......但这只会在特定情况下有用。您可以使多个Parameters构造函数表示不同的参数排列,但您调用的函数只接受一个输入 - Parameters对象。所以有了这个,你真的会破坏重载函数的能力。

所以,简而言之,没有。 =)

答案 13 :(得分:0)

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