tags:

views:

630

answers:

14

Is there any way to do something like this in C#?

public void DoSomething(string parameterA, int parameterB)
{

}

var parameters = ("someValue", 5);
DoSomething(parameters);
+4  A: 

nope - this is not possible.

this. __curious_geek
+8  A: 

You can invoke it through reflection, but that'll incur some overhead:

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

Of course, if you can change the method signature to take an array, that'll work as well, but that will look worse in my opinion.

Lasse V. Karlsen
Couldn't you just do `Action<string, int> m = p.DoSomething; m.DynamicInvoke(parameters);`?
Dan Tao
*gah*, yes, that is a better solution! long day, too little coffee, yaddayaddayadda. Please upvote spenders answer.
Lasse V. Karlsen
+19  A: 

Close, but unfortuantely only using object (so you get lots of boxing/unboxing)

public void DoSomething(params object[] parameters)
{

}

var parameters = new object[]{"someValue", 5};
DoSomething(parameters); // this way works
DoSomething("someValue", 5); // so does this way
Jamiec
+1 for getting as close as might be possible without resorting to reflection (or delegate invocation).
stakx
I thought he said a requirement was not to change the method signature? He even put that requirement in bold, lol, then marks this as the answer!
AaronLS
@AaronLS: Yes, but this is the only way, although it's not perfect...
TTT
Spenders answer is the closest one. It's like "How can I do X without doing Y", with "You can do X if you do Y" and then "Great, good answer".
Lasse V. Karlsen
@Alon Actually it is not the only way, keep scrolling and there are a couple other ways. LOL
AaronLS
Edited question. Now can you stop please with those stupid comments?
TTT
+1  A: 

If they're all the same type, yes, you can do something to this effect:

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

Otherwise, no, you can't expand parameters in place like that without using reflection. C# doesn't have the equivalent of Ruby's splat operator.

John Feminella
+2  A: 

You can do this (.NET 4.0):

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

DoSomething(parameters.Item1, parameter.Item2);
Steven
I think this answer misses the point. This would be closer to what's been asked if the `DoSomething` function would accept the **tuple** and "unpack" it across the original parameters. (But C# doesn't have such a feature.)
stakx
I agree - this doesn't solve the problem asked at all (interesting as it may be).
Dan Diplo
@stakx: The addition of this "feature" is quite straightforward using an extension method, though. Take a look at Henrik's answer.
Dan Tao
@Dan Tao: Interesting as Henrik's answer might be, it doesn't meet the semantics that the OP asked for. It actually reverses the order: `function(arguments)` becomes `arguments.Execute(function)`. (I don't mean to be overly pedantic btw., but merely would like to point out that C# doesn't truly support the exact feature in question.)
stakx
@stakx: That's why in a comment to Henrik's answer I suggested inverting the order... gahhh I'm just going to post my own answer!
Dan Tao
@stakx: See *my* answer now; it's *almost* what the OP was asking for. What Henrik suggested really wasn't far off.
Dan Tao
+9  A: 

No need to use reflection if you first store as a delegate, but it does require a strong declaration of the delegate.

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

}

...and you can forget about compile-time type/sanity checking of the parameter list. Probably a bad thing.

spender
A: 

"var" just represents a particular type, it's effectively shorthand for writing a type name. In the above you're not specifying any type. The only way to do this is to make a parameter class to represent the inputs in bulk...

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

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

...but this is only going to be useful in specific circumstances. You could make multiple Parameters constructors to represent different arrangements of parameters, but the function you're calling will only take ONE input - the Parameters object. So with this you're really undermining the ability to overload a function.

So, in short, no. =)

Joel Goodwin
+2  A: 

you can do:

public void DoSomething(string parameterA, int parameterB)
{

}

var func = (Action)(() => DoSomething("someValue", 5));
func();
Andrey
Haha, I like that: `var func = (Action)(...)`. A fan of misdirection, are you?
Dan Tao
@Dan Tao what is so funny?
Andrey
@Andrey: You've got an `Action`, which you've called `func`, and you declared it with `var`. To me that's like writing `var float = (double)2.5;` ... OK, OK, maybe it's not that funny. But you *could've* just written `Action action = () => DoSomething("someValue", 5);`
Dan Tao
+3  A: 

Maybe this way is more "clean":

// 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;
    }
}
TcKs
Nice, add some explaining text too :)
Filip Ekberg
@Filip: ok, as you wish :)
TcKs
Not as comments!! ;)
Filip Ekberg
A: 

How about this in .NET 4 (for the sake of curiosity)

 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);
Ithryn
+3  A: 

Inspired by Steven's answer:

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);
Henrik
I was going to suggest the same thing. Except, I think it makes more sense to make `Execute` an extension method on `Action`, don't you? So: `((Action<string, int>)DoSomething).Execute(parameters);` It's convenient that yours doesn't require casting to `Action`, but it's also kind of bizarre to think of parameters executing an action.
Dan Tao
+1 Very nice one.
Steven
+1  A: 

If you don't want to change the method signature why not declare a new method with the appropriate signature and use that as a proxy. Like

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

You can also try out some of the stuff LinFu.Reflection provides, like Late Binding. With it you can do something like this:

var dosomethingobject = new ObjectThatHasTheDoSomething();
DynamicObject dynamic = new DynamicObject(dosomethingobject);

var parameters = new object[]{"someValue", 5};
dynamic.Methods["DoSomething"](parameters);

For this you need that the DoSomething method is inside an object.

SztupY
+14  A: 

Not today, no. We are at present prototyping exactly that feature for a possible hypothetical future version of C#.

If you can provide a really awesome reason why you want this feature, that would be points towards actually getting it out of prototyping and into a possible hypothetical future release. What's your awesome scenario that motivates this feature?

(Remember, Eric's speculations about possible hypothetical future releases of C# are for entertainment purposes only and are not to be construed as promises that there ever will be such a release or that it will have any particular feature set.)

Eric Lippert
+1 for the end :)
RCIX
+3  A: 

I like Henrik's answer, except that it imposes a somewhat weird syntax: parameters call a method on themselves. I would do it the other way around. Only problem with this approach is that it makes you explicitly cast a method to a delegate.

Anyway, here's the basic idea:

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

And so on (for more Ts).

Usage:

var parameters = Tuple.Create("Hi", 10);

Action<string, int> action = DoSomething;

action.Execute(parameters);

You can also easily do this with a return value:

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

And so on.

I'd also like to point out that just because you aren't on .NET 4.0, that doesn't mean you can't easily implement your own Tuple<T1, T2, ...> type.

Dan Tao