Is there a way to get an array of the arguments passed to a method?

后端 未结 9 1259
小蘑菇
小蘑菇 2020-12-05 18:17

Say I have a method:

 public void SomeMethod(String p1, String p2, int p3)
 {

 #if DEBUG
    object[] args = GetArguments();
    LogParamaters(args);
 #endi         


        
相关标签:
9条回答
  • 2020-12-05 18:24

    If you use Postsharp you can simply add an attribute to the method you want to log. Within this attribute you can write the logging code and also will provide the arguments you need. This is known as cross cutting concerns and AOP (Aspect orientated programming)

    0 讨论(0)
  • 2020-12-05 18:26

    Here's what I came up with as a solution:

    PostSharp or another AOP solution wasn't really practical in this situation, so unfortunately I had to abandon that idea.

    It appears that while it is possible to parameter names and types using reflection, the only way to access the runtime values is with a debugger attached.

    See here for more info:

    StackOverflow

    microsoft.public.dotnet.framework

    So that still left me with the problem of ~50 methods that needed this logging adding by hand.

    Reflection to the rescue...

    public String GetMethodParameterArray()
        {
            var output = new StringBuilder();
            output.AppendLine();
    
            Type t = typeof(API);
            foreach (var mi in t.GetMethods())
            {
                    var argsLine = new StringBuilder();
                    bool isFirst = true;
                    argsLine.Append("object[] args = {");
                    var args = mi.GetParameters();
    
                    foreach (var pi in args)
                    {
                        if (isFirst)
                        {
                            isFirst = false;
                        }
                        else
                        {
                            argsLine.Append(", ");
                        }
                        argsLine.AppendFormat("{0}", pi.Name);
                    }
                    argsLine.AppendLine("};"); //close object[] initialiser
    
                    output.AppendLine(argsLine.ToString());
                    output.AppendFormat("Log(\"{0}\",args);", mi.Name);
                    output.AppendLine();
                    output.AppendLine();
                }
            return output.ToString();
        }
    

    This code snippet loops through the methods on a class and outputs an object[] array initialised with the arguments passed into the method and a Log call containing the arguments and the method name.

    Example output:

    object[] args = {username, password, name, startDate, endDate, cost};
    Log("GetAwesomeData",args);
    

    This block can then be pasted into the top of the method to achieve the required effect.

    It is more manual than I would have liked, but it is a lot better than having to type the parameters by hand and far less error prone.

    0 讨论(0)
  • 2020-12-05 18:27

    I am unsure if the API to access the call stack provides a means to get the argument list.

    However there are ways to inject IL to intercept method calls and execute custom code.

    The Library I use frequently is PostSharp by Gael Fraiteur, it includes an application that runs postbuild and injects IL in your output assemblies depending on the Aspects that you are using. There are attributes with which you can decorate assemblies, types, or individual methods. For instance:

    [Serializable]
    public sealed class LoggingAttribute : OnMethodBoundaryAspect
    {
        public override void OnEntry(MethodExecutionArgs eventArgs)
        {
            Console.WriteLine("Entering {0} {1} {2}",
                              eventArgs.Method.ReflectedType.Name,
                              eventArgs.Method,
                              string.Join(", ", eventArgs.Arguments.ToArray()));
    
            eventArgs.MethodExecutionTag = DateTime.Now.Ticks;
        }
    
        public override void OnExit(MethodExecutionArgs eventArgs)
        {
            long elapsedTicks = DateTime.Now.Ticks - (long) eventArgs.MethodExecutionTag;
            TimeSpan ts = TimeSpan.FromTicks(elapsedTicks);
    
            Console.WriteLine("Leaving {0} {1} after {2}ms",
                              eventArgs.Method.ReflectedType.Name,
                              eventArgs.Method,
                              ts.TotalMilliseconds);
        }
    }
    

    After this you can just decorate the method you want with this Attribute:

    [Logging]
    public void SomeMethod(String p1, String p2, int p3) 
    {
       //..
    }
    
    0 讨论(0)
  • 2020-12-05 18:27

    Sure can ...check out this post, it gets the actual values of the params. how to enumerate passed method parameters

    0 讨论(0)
  • 2020-12-05 18:32

    There's some functionality with the dynamic type system that can do it, but then your class needs to inherit from the dynamic base classes

    0 讨论(0)
  • 2020-12-05 18:36

    might not work in some scenarios but should get you started :)

    class Program
    {
        static void Main(string[] args)
        {
            M1("test");
            M2("test", "test2");
            M3("test", "test2", 1);
    
            Console.ReadKey();
        }
    
        static void M1(string p1)
        {
            Log(MethodBase.GetCurrentMethod());
        }
    
        static void M2(string p1, string p2)
        {
            Log(MethodBase.GetCurrentMethod());
        }
    
        static void M3(string p1, string p2, int p3)
        {
            Log(MethodBase.GetCurrentMethod());
        }
    
        static void Log(MethodBase method)
        {
            Console.WriteLine("Method: {0}", method.Name);
            foreach (ParameterInfo param in method.GetParameters())
            {
                Console.WriteLine("ParameterName: {0}, ParameterType: {1}", param.Name, param.ParameterType.Name);
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题