开发者

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

开发者 https://www.devze.com 2022-12-28 13:43 出处:网络
Is there any way to do something like this in C#? public void DoSomething(string 开发者_如何学PythonparameterA, int parameterB)

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

public void DoSomething(string 开发者_如何学PythonparameterA, int parameterB)
{

}

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


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


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


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.


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.


nope - this is not possible.


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


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


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.


you can do:

public void DoSomething(string parameterA, int parameterB)
{

}

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


You can do this (.NET 4.0):

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

DoSomething(parameters.Item1, parameter.Item2);


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.


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.


"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. =)


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

精彩评论

暂无评论...
验证码 换一张
取 消