简体   繁体   English

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

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

Is there any way to do something like this in C#? 有没有办法在C#中做这样的事情?

public void DoSomething(string parameterA, 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#. 我们目前正在为可能的假设未来版本的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对C#可能假设的未来版本的推测仅用于娱乐目的,不应被解释为承诺将会有这样的版本,或者它将具有任何特定的功能集。)

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. 当然,如果您可以更改方法签名以获取数组,那么它也会起作用,但在我看来这看起来会更糟糕。

- 这是不可能的。

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. 我喜欢Henrik的答案,除了它强加了一些奇怪的语法:参数调用自己的方法。 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 T s). 等等(更多T s)。

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. 我还想指出,仅仅因为你不在.NET 4.0上,这并不意味着你不能轻易地实现你自己的Tuple<T1, T2, ...>类型。

You can do this (.NET 4.0): 你可以这样做(.NET 4.0):

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

DoSomething(parameters.Item1, parameter.Item2);

you can do: 你可以做:

public void DoSomething(string parameterA, int parameterB)
{

}

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

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 . C#没有Ruby的splat运算符

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. 你也可以尝试LinFu.Reflection提供的一些东西,比如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. 为此,您需要DoSomething方法位于对象内。

"var" just represents a particular type, it's effectively shorthand for writing a type name. “var”只表示一种特定的类型,它是写入类型名称的有效简写。 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. 您可以使多个Parameters构造函数表示不同的参数排列,但您调用的函数只接受一个输入 - Parameters对象。 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) 在.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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 c#我可以为“if”这样做吗? 或任何其他方式做这样的事情? - c# Can I do this for “if”? or any other way to doing something like this? 有没有办法完成像List这样的事情 <object> list =新列表 <int> ()在C#? - Is there any way to accomplish something like List<object> list = new List<int>() in C#? 有什么办法可以在Winforms中执行Slider.AutoToolTipPlacement之类的操作吗? - Is there any way to do something like Slider.AutoToolTipPlacement in Winforms? 有没有办法像这样过滤 C# DataView? - Is there any way to filter C# DataView like this? C#是否执行Windows窗体的动态继承之类的操作? - C# Do something like dynamic inheritance for Windows Forms? 在C#中我们可以做这样的List <? of CustomType> - in C# can we do something like this List<? of CustomType> 如何做“类 <? extends MyClass > “在C#中 - How to do something like “Class<? extends MyClass >” in C# 他们是C#中的iframe吗? - Is their something like iframe in C#? 在 c# 中类似于 static this - Is something like static this in c# 在C#中,有没有一种方法可以将诸如Microsoft.VisualBasic.Interaction.MsgBox()之类的引用调用缩短为诸如myMsgBox()之类的引用? - In C# is there a way to shorten reference calls like Microsoft.VisualBasic.Interaction.MsgBox() to something like myMsgBox()?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM