Finding the variable name passed to a function

前端 未结 17 1946
广开言路
广开言路 2020-11-22 04:11

Let me use the following example to explain my question:

public string ExampleFunction(string Variable) {
    return something;
}

string WhatIsMyName = "         


        
相关标签:
17条回答
  • 2020-11-22 04:46

    This would be very useful to do in order to create good exception messages causing people to be able to pinpoint errors better. Line numbers help, but you might not get them in prod, and when you do get them, if there are big statements in code, you typically only get the first line of the whole statement.

    For instance, if you call .Value on a nullable that isn't set, you'll get an exception with a failure message, but as this functionality is lacking, you won't see what property was null. If you do this twice in one statement, for instance to set parameters to some method, you won't be able to see what nullable was not set.

    Creating code like Verify.NotNull(myvar, nameof(myvar)) is the best workaround I've found so far, but would be great to get rid of the need to add the extra parameter.

    0 讨论(0)
  • 2020-11-22 04:47

    Three ways:

    1) Something without reflection at all:

    GetParameterName1(new { variable });
    
    public static string GetParameterName1<T>(T item) where T : class
    {
        if (item == null)
            return string.Empty;
    
        return item.ToString().TrimStart('{').TrimEnd('}').Split('=')[0].Trim();
    }
    

    2) Uses reflection, but this is way faster than other two.

    GetParameterName2(new { variable });
    
    public static string GetParameterName2<T>(T item) where T : class
    {
        if (item == null)
            return string.Empty;
    
        return typeof(T).GetProperties()[0].Name;
    }
    

    3) The slowest of all, don't use.

    GetParameterName3(() => variable);
    
    public static string GetParameterName3<T>(Expression<Func<T>> expr)
    {
        if (expr == null)
            return string.Empty;
    
        return ((MemberExpression)expr.Body).Member.Name;
    }
    

    To get a combo parameter name and value, you can extend these methods. Of course its easy to get value if you pass the parameter separately as another argument, but that's inelegant. Instead:

    1)

    public static string GetParameterInfo1<T>(T item) where T : class
    {
        if (item == null)
            return string.Empty;
    
        var param = item.ToString().TrimStart('{').TrimEnd('}').Split('=');
        return "Parameter: '" + param[0].Trim() +
               "' = " + param[1].Trim();
    }
    

    2)

    public static string GetParameterInfo2<T>(T item) where T : class
    {
        if (item == null)
            return string.Empty;
    
        var param = typeof(T).GetProperties()[0];
        return "Parameter: '" + param.Name +
               "' = " + param.GetValue(item, null);
    }
    

    3)

    public static string GetParameterInfo3<T>(Expression<Func<T>> expr)
    {
        if (expr == null)
            return string.Empty;
    
        var param = (MemberExpression)expr.Body;
        return "Parameter: '" + param.Member.Name +
               "' = " + ((FieldInfo)param.Member).GetValue(((ConstantExpression)param.Expression).Value);
    }
    

    1 and 2 are of comparable speed now, 3 is again sluggish.

    0 讨论(0)
  • 2020-11-22 04:48

    You could use reflection to get all the properties of an object, than loop through it, and get the value of the property where the name (of the property) matches the passed in parameter.

    0 讨论(0)
  • 2020-11-22 04:49

    Yes! It is possible. I have been looking for a solution to this for a long time and have finally come up with a hack that solves it (it's a bit nasty). I would not recommend using this as part of your program and I only think it works in debug mode. For me this doesn't matter as I only use it as a debugging tool in my console class so I can do:

    int testVar = 1;
    bool testBoolVar = True;
    myConsole.Writeline(testVar);
    myConsole.Writeline(testBoolVar);
    

    the output to the console would be:

    testVar: 1
    testBoolVar: True
    

    Here is the function I use to do that (not including the wrapping code for my console class.

        public Dictionary<string, string> nameOfAlreadyAcessed = new Dictionary<string, string>();
        public string nameOf(object obj, int level = 1)
        {
            StackFrame stackFrame = new StackTrace(true).GetFrame(level);
            string fileName = stackFrame.GetFileName();
            int lineNumber = stackFrame.GetFileLineNumber();
            string uniqueId = fileName + lineNumber;
            if (nameOfAlreadyAcessed.ContainsKey(uniqueId))
                return nameOfAlreadyAcessed[uniqueId];
            else
            {
                System.IO.StreamReader file = new System.IO.StreamReader(fileName);
                for (int i = 0; i < lineNumber - 1; i++)
                    file.ReadLine();
                string varName = file.ReadLine().Split(new char[] { '(', ')' })[1];
                nameOfAlreadyAcessed.Add(uniqueId, varName);
                return varName;
            }
        }
    
    0 讨论(0)
  • 2020-11-22 04:52

    This isn't exactly possible, the way you would want. C# 6.0 they Introduce the nameof Operator which should help improve and simplify the code. The name of operator resolves the name of the variable passed into it.

    Usage for your case would look like this:

    public string ExampleFunction(string variableName) {
        //Construct your log statement using c# 6.0 string interpolation
        return $"Error occurred in {variableName}";
    }
    
    string WhatIsMyName = "Hello World";
    string Hello = ExampleFunction(nameof(WhatIsMyName));
    

    A major benefit is that it is done at compile time,

    The nameof expression is a constant. In all cases, nameof(...) is evaluated at compile-time to produce a string. Its argument is not evaluated at runtime, and is considered unreachable code (however it does not emit an "unreachable code" warning).

    More information can be found here

    Older Version Of C 3.0 and above
    To Build on Nawfals answer

    GetParameterName2(new { variable });
    
    //Hack to assure compiler warning is generated specifying this method calling conventions
    [Obsolete("Note you must use a single parametered AnonymousType When Calling this method")]
    public static string GetParameterName<T>(T item) where T : class
    {
        if (item == null)
            return string.Empty;
    
        return typeof(T).GetProperties()[0].Name;
    }
    
    0 讨论(0)
  • 2020-11-22 04:59
    static void Main(string[] args)
    {
      Console.WriteLine("Name is '{0}'", GetName(new {args}));
      Console.ReadLine();
    }
    
    static string GetName<T>(T item) where T : class
    {
      var properties = typeof(T).GetProperties();
      Enforce.That(properties.Length == 1);
      return properties[0].Name;
    }
    

    More details are in this blog post.

    0 讨论(0)
提交回复
热议问题