有没有办法在C#中做这样的事情?
public void DoSomething(string parameterA, int parameterB)
{
}
var parameters = ("someValue", 5);
DoSomething(parameters);
答案 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);