22
void MyMethod(string something, params 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.)

Bakudan
  • 19,134
  • 9
  • 53
  • 73
Niels Brinch
  • 3,033
  • 9
  • 48
  • 75
  • 4
    I can't wait to find out what you would do with this information. – Gabe May 17 '11 at 03:24
  • 1
    OK, I'll give you the good laugh you've deserved. I was just curious about sweetening up the syntax for a database update wrapper method where the parameter name in C# would be the parameter name used in the SQL command. – Niels Brinch May 17 '11 at 03:42
  • 1
    You could use a syntax like `MyMethod("test", new { myFirstParam = "some kind of text", anotherParam = 42});` if you want to use anonymous types like MVC does. See http://weblogs.asp.net/leftslipper/archive/2007/09/24/using-c-3-0-anonymous-types-as-dictionaries.aspx for some trivial code to make it work. – Gabe May 17 '11 at 05:46
  • Neat - and **then** I would be able to use reflection to get the property name. Very nice. Thanks. – Niels Brinch May 17 '11 at 08:52
  • 1
    and then! i would use dynamic object's method missing goodness to not have to write a new method for each 'sql command', so you could just write dbWrapper.whateverMethod(new { param1 = 'foo', param2 = 'bar'}) and be able to grab that 'whateverMethod' is the sproc you want to call – IAmCodeMonkey May 20 '11 at 14:36
  • Ha ha, beautiful! (if using stored procedures) – Niels Brinch May 29 '11 at 09:35
  • I looked this up because I have a constructor that throws 6 `ArgumentNullException` for its args. Wanted to see if I could create a static method to throw for me. Guess not. That was my potential use-case though. – Jonesopolis Jan 06 '16 at 15:31

8 Answers8

32

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.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • would it work in other cases though, where there actually was a parameter passed? Using reflection? – richard May 17 '11 at 03:19
  • 3
    @Richard: No; that's not what reflection does. You would need a decompiler, and a symbol file. – SLaks May 17 '11 at 03:20
  • Oh right, I forgot. You can get method names etc, but you don't actually get the symbols of parameters etc. as if they were decompiled. Thanks for the clarification. :-) – richard May 17 '11 at 03:25
  • Thanks a lot (all of you). I know it doesn't make sense in many cases, but having a conclusive answer that it is simply not possible, because the information is not there, is what I was looking for. Thanks. – Niels Brinch May 17 '11 at 03:32
  • 1
    This is no longer correct as of c#10,, please see c# 10 answers here. – tymtam Nov 03 '22 at 00:31
8

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
tymtam
  • 31,798
  • 8
  • 86
  • 126
6

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")
{
}
shingo
  • 18,436
  • 5
  • 23
  • 42
2

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.

Andrew Savinykh
  • 25,351
  • 17
  • 103
  • 158
0

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.

freewill
  • 1,111
  • 1
  • 10
  • 23
0

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.

Community
  • 1
  • 1
Richard Matsen
  • 20,671
  • 3
  • 43
  • 77
0

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

IAmCodeMonkey
  • 1,576
  • 1
  • 11
  • 11
  • There is certainly a good reason for it... for example I am trying to create a generic SQL Proc reading/binding method, and by convention, the C# vars would have the same name as the proc params, if I could find out the name of the passed in params, I would be easily able to create my `SqlParameter`s, but now I have to call the proc 2x, first to get the parameter names, second to actually get the data I need... – Serj Sagan Mar 30 '15 at 17:29
  • Possible in c#10,, please see c# 10 answers here. – tymtam Sep 29 '22 at 07:23
-1

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!

Martin
  • 152
  • 10
  • 3
    That just passes the name of the variable to the function in a type-safe manner - it does not allow the function to reach back and get the variable names from the function that called it. The reasons as to why this is impossible have not changed. – D Stanley Nov 14 '14 at 18:16
  • You can pass the name of the parameter in as a ... Parameter – Martin Nov 14 '14 at 23:09
  • 1
    But the original question was how to get the name of the variable used _by the calling method_. `nameof` deosn't add any new functionality, it just allows you to use a variable insyead pr a string (you could do the same thing in your example with `throw new ArgumentException("bar");` – D Stanley Nov 15 '14 at 14:16
  • Yes, it's not what I was looking for. But thanks otherwise, this is also a very cool feature. – Niels Brinch Feb 13 '15 at 13:34
  • 1
    As was stated, this does not get the name of the passed in vars, only the name of the param variable itself... completely irrelevant to the asked question. the question is asking for this: given `myMethod(paramName1, paramName2)` in `myMethod(params object[] myParams)` how do I get `paramName1` and `paramName2`, we don't care about the name of `myParams` – Serj Sagan Mar 30 '15 at 18:16