is it possible to get collection of passed-in values in a method call ?
I would like to get values of parameters for logging/debuging purposes.
e.g
private void DoSomeBusinessLogic(int a, int b, String c,...)
{
//get somehow values of the method
Object[] paramterValuesCollection = ?
LogParamValues(paramterValuesCollection);
//countinue with business logic
...
}
static void LogParamValues(Object[] values)
{
foreach (Object nextParam in values)
{
//Log params...
}
}
Of course I would like to apply the pattern in many different functions with
different signatures, so I cannot simply "hardcode" parameters' references. I
need to extract parameter values dynamically, at runtime.
Best Regards,
Michał Januszczyk
john conwell - 05 Oct 2005 18:26 GMT
Let me just say that using this kind of generic pattern will move you away
from compile time string type checking as well as introduce a drastic
performance issue. There might be a way with reflection, but i would
strongly suggest you stay away from that.
you could use the "params" keyword in C# (now sure what the VB equivilent
is). this allows you to have one parm that is an object[] and you can pass
in 0 to many parameters of any type. No you will have boxing and unboxing
performance issues here, it'll probably be better than anything you could
come up with via reflection.
here is an example of the params from MSDN:
public static void UseParams(params int[] list)
{
for ( int i = 0 ; i < list.Length ; i++ )
Console.WriteLine(list[i]);
Console.WriteLine();
}
public static void UseParams2(params object[] list)
{
for ( int i = 0 ; i < list.Length ; i++ )
Console.WriteLine(list[i]);
Console.WriteLine();
}
public static void Main()
{
UseParams(1, 2, 3);
UseParams2(1, 'a', "test");
int[] myarray = new int[3] {10,11,12};
UseParams(myarray);
}
> is it possible to get collection of passed-in values in a method call ?
>
[quoted text clipped - 29 lines]
> Best Regards,
> Michał Januszczyk
Nick Hertl - 05 Oct 2005 18:38 GMT
What you are asking for basically comes down to in-process debugging.
You want to be able to know the values of the parameters to your
function at runtime from inside your own process.
Currently, System.Reflection will allow you to get the CurrentMethod
and then call GetParameters to know what they are called, but this does
not actually provide the values of those parameters. You can do
similar tricks using the System.Diagnostics.StackTrace and StackFrame
class to get information about the functions and arguments, but still
this is all without getting the values.
Support for what you are trying to do may be added in future versions
of the Common Language Runtime, but currently the best way to do this
is by writting a custom debugger that can run alongside your
application and provide the information that you need from out of
process.
You would need to have your original application make calls out to this
second process requesting a log. The custom debugger would then
basically freeze execution, get all the info that it needs, inject it
into the original process through function evaluation or a method
similar to how you called into the debugger. Once the debugger has the
values you need and passes them to the original process, it can allow
it to resume.
This method is great because you can simply insert identical function
calls at every point that you want a log.
This method is not so great because it's a lot of work and may
significantly modify its performance.
I assume that you are going to write some script to drop these calls
into every function where you need it right?
Have you considered just making that script smart enough to pass an
object[] that contains all the arguments that it found in that function
signature?
I would not recommend the above suggestion of changing all your
functions to take variable length parameters. That is just asking for
disaster.
Dustin Campbell - 06 Oct 2005 00:26 GMT
Hi,
This is easily done using System.Diagnostics.StackTrace,
System.Diagnostics.StackFrame and reflection. The only real trick is
to be careful of out parameters.
using System;
using System.Diagnostics;
using System.Reflection;
using System.Text;
namespace ConsoleApplication1
{
class TestClass
{
// entry point...
[STAThread]
private static void Main()
{
LogMethod();
SimpleTest("Test", -1);
int lValue;
MethodWithOut("Test", out lValue, true);
}
private static void SimpleTest(string text, int id)
{
LogMethod(text, id);
}
private static void MethodWithOut(string arg1, out int arg2, bool
arg3)
{
LogMethod(arg1, arg3);
arg2 = 0;
}
private static void LogMethod(params object[] args)
{
// Get calling method...
StackTrace lCallStack = new StackTrace(1, true);
StackFrame lCallingMethodFrame = lCallStack.GetFrame(0);
MethodBase lCallingMethod = lCallingMethodFrame.GetMethod();
// If there aren't any argmuments, we're done.
if (args == null || args.Length == 0)
{
Debug.WriteLine(lCallingMethod.Name + "( )");
return;
}
ParameterInfo[] lParameters = lCallingMethod.GetParameters();
// Count number of "in" parameters.
int lInParamCount = lParameters.Length;
foreach (ParameterInfo lParameter in lParameters)
if (lParameter.IsOut)
lInParamCount--;
Debug.Assert(lInParamCount == args.Length,
String.Format("Incorrect number of arguments. Expected {0} but was
{1}.", lParameters.Length, args.Length));
StringBuilder lSignature = new StringBuilder();
lSignature.Append(lCallingMethod.Name);
lSignature.Append("( ");
int lParamCount = lParameters.Length;
int lArgIndex = 0;
for (int i = 0; i < lParamCount; i++)
{
lSignature.Append(lParameters[i].Name);
lSignature.Append(" = ");
if (lParameters[i].IsOut)
lSignature.Append("<Unknown>");
else
{
if (args[lArgIndex] == null)
lSignature.Append("<null>");
else
lSignature.Append(args[lArgIndex].ToString());
lArgIndex++;
}
if (i < lParamCount - 1)
lSignature.Append(", ");
}
lSignature.Append(" )");
Debug.WriteLine(lSignature.ToString());
}
}
}
--------
Best Regards,
Dustin Campbell
Developer Express, Inc
Robert Jordan - 06 Oct 2005 01:24 GMT
Hi Dustin,
> private static void LogMethod(params object[] args)
> {
> // Get calling method...
> StackTrace lCallStack = new StackTrace(1, true);
> StackFrame lCallingMethodFrame = lCallStack.GetFrame(0);
> MethodBase lCallingMethod = lCallingMethodFrame.GetMethod();
The StackFrame trick won't work when the method gets inlined
by the JIT (not in DEBUG mode).
Rob
Dustin Campbell - 06 Oct 2005 02:32 GMT
>The StackFrame trick won't work when the method gets inlined
>by the JIT (not in DEBUG mode).
True. But, for debugging purposes, this is fine. To make this a bit
safer add the a ConditionalAttribute to LogMethod like this:
[Conditional("DEBUG")]
private static void LogMethod(params object[] args)
That way, this method will only execute when DEBUG is defined.
--------
Best Regards,
Dustin Campbell
Developer Express, Inc
Michał Januszczyk - 06 Oct 2005 13:53 GMT
Thank You all guys. I'll try to use Dustin's approach.
Best Regards,
Michał