开发者

Get names of the params passed to a C# method

void MyMethod(string something, par开发者_StackOverflowams object[] parameters)
    {
      foreach (object parameter in parameters)
      {
        // Get the name of each passed parameter
      }
    }

For example, if I call the method in the following way, I want to get the names "myFirstParam" and "anotherParam".

string myFirstParam = "some kind of text";
string anotherParam = 42;
MyMethod("test", myFirstParam, anotherParam);

Perhaps reflection is the answer? Perhaps it's just not possible? I am aware of the existance of this question, but that solution won't work here.

(Please do not respond with "This is not a good idea". That is not my question.)


This is totally impossible.

Here are just a few cases where it doesn't even make sense:

MyMethod("abc", new object[5]);
MyMethod("abc", "def");
MyMethod("abc", var1 + var2);
MyMethod("abc", SomeMethod());
MyMethod("abc", b ? a : c);
MyMethod("abc", new object()); 
MyMethod("abc", null);

In fact, local variable names aren't even compiled into the assembly.


Building on @shingo's answer.

Since C#10, you can get the name of the variable passed using CallerArgumentExpressionAttribute Class.

This is .NET6:

using System.Runtime.CompilerServices;

void F(object arg1, [CallerArgumentExpression("arg1")] string arg1Exp = "?")
    => Console.WriteLine($"{arg1Exp} => {arg1}");

var var1 = "C#10";
var var2 = "_";
var b = var1.Length > 7;

F(var1);
F(new object[5]);
F("def");
F(var1 + var2);
F(SomeMethod());
F(b ? var1 : var2);
F(new object()); 
F(null);
F(int.Parse(var1.Substring(2)) switch {
     >= 10 => "Supported",
     _ => "Not supported"
});

int SomeMethod() => 7 + 8;

Output (which seems magical):

var1 => C#10
new object[5] => System.Object[]
"def" => def
var1 + var2 => C#10_
SomeMethod() => 15
b ? var1 : var2 => _
new object() => System.Object
null => 
int.Parse(var1.Substring(2)) switch {
     >= 10 => "Supported",
     _ => "Not supported"
} => Supported


C# 10 has introduced a new attribute CallerArgumentExpressionAttribute.

Getting names from params parameters is still impossible, but if you have fixed number of parameters (like overload methods), then it's possible.

void MyMethod(object p0,
    [CallerArgumentExpression("p0") string p0exp = "p0")
{
    Console.WriteLine(p0exp);
}

void MyMethod(object p0, object p1,
    [CallerArgumentExpression("p0") string p0exp = "p0",
    [CallerArgumentExpression("p1") string p1exp = "p1")
{
}


In addition to SLaks's answer - variable names are not available at run-time at all. The variables are represented by stack slots and are addressed by an index. Thus you can't get this information even for the example you provided, not to mention all these examples SLaks provided. Reflection is no help here. Nothing is.


It is not possible, and I wonder why you would need that.


I RAISE THIS QUESTION FROM THE DEAD!

Check out C# 6.0's new nameof() operator. It allows you to do exactly what you want, and it actually isn't always a bad idea.

A good use case is Argument Exceptions, or INotifyPropertyChanged. (Especially when you get inheritance in the mix)

Example:

interface IFooBar
{
    void Foo(object bar);
}

public class FooBar : IFooBar
{


    public void Foo(object bar)
    {
        if(bar == null)
        {
            //Old and Busted
            //throw new ArgumentException("bar");

            //The new HOTNESS
            throw new ArgumentException(nameof(bar)); // nameof(bar) returns "bar"

        }

        //....
    }

}

Now, if you were rename the parameter 'bar' on the method 'Foo' in the interface IFooBar, your argument exceptions would update accordingly (prevents you from forgetting to change the "bar" string)

Pretty neat actually!


What about this;

void MyMethod(string something, object parameters)
{
RouteValueDictionary dic = HtmlHelper.AnonymousObjectToHtmlAttributes(options);
}

MyMethod("test", new { @myFirstParam=""some kind of text", anotherParam=42);

This has already been implemented in System.Web.MVC.Html InputExtension.

I was inspired and using this technique in my code. It is very flexible.

Dont bother about "Html" naming in the helper methods. There is nothing to do with html, or html attributes inside the helper method.

It just converts named, anonymous arguments to RouteValueDictionary, a special dictionary having IDictionary<string,object> interface where key holds the argument name and object is the value of the argument.


Using reflection, and @Martin's example of null argument testing:

using System.Reflection;

public SomeMethod(ClassA a, ClassB b, ClassC c)
{
    CheckNullParams(MethodBase.GetCurrentMethod(), a, b, c);
    // do something here
}

accessing the parameter names:

public void CheckNullParams(MethodBase method, params object[] args)
{
    for (var i=0; i < args.Count(); i++)
    {
        if (args[i] == null)
        {
            throw new ArgumentNullException(method.GetParameters()[i].Name);
        }
    }
}

This works with constructors and public methods, but I haven't tested beyond unit tests within VS, so possibly there are some runtime JIT issues (reading through articles referenced above).

EDIT: Just noticed, this is essentially the same as linked answer.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜