Passing an array as `params` argument - c#

I have the following method:
void MyMethod(params object[] args)
{
}
which I am trying to call with a parameter of type object[]:
object[] myArgs = GetArgs();
MyMethod(myArgs);
It compiles fine, but inside MyMethod I args == { myArgs}, i.e. an array with one element that is my original arguments. Obviously I wanted to have args = myArgs, what am I doing wrong?
EDIT:
Jon Skeet was actually right, the GetArgs() did wrap the thing in an one element array, sorry for stupid question.

What you've described simply doesn't happen. The compiler does not create a wrapper array unless it needs to. Here's a short but complete program demonstrating this:
using System;
class Test
{
static void MyMethod(params object[] args)
{
Console.WriteLine(args.Length);
}
static void Main()
{
object[] args = { "foo", "bar", "baz" };
MyMethod(args);
}
}
According to your question, this would print 1 - but it doesn't, it prints 3. The value of args is passed directly to MyMethod, with no further expansion.
Either your code isn't as you've posted it, or the "wrapping" occurs within GetArgs.
You can force it to wrap by casting args to object. For example, if I change the last line of Main to:
MyMethod((object) args);
... then it prints 1, because it's effectively calling MyMethod(new object[] { args }).

Related

TargetParameterCountException: Parameter count mismatch on invoke - delegate

I have the following code (removed unrelated)
//top of class declaration
private delegate void UpdateFormElements(string status, bool addEmptyRow);
//inside a function in my class
if(lboImages.InvokeRequired)
{
lboImages.Invoke((UpdateFormElements)delegate { UpdateListBox("some text", true); });
}
private void UpdateListBox(string line, bool addEmptyRow)
{
lboImages.Items.Add(line);
if (addEmptyRow)
{
lboImages.Items.Add("");
}
}
Basically I'm trying to pass two parameters to the UpdateListBox function to test whether to add an empty line or not to my listbox, but I am getting the error in the title. I have tried putting the two values in an object[] but it doesn't seem to change anything as I still get the error.
I'm still new to using threads so not really sure where I'm going wrong here.
It's not clear why you're trying to use an anonymous method here. The problem is that you're creating a delegate type with two parameters, but you're not passing arguments (values for those parameters) into Invoke.
I suspect you just want:
lboImages.Invoke((UpdateFormElements) UpdateListBox, "some text", true));
That uses a method group conversion to create an UpdateFormElements delegate, and provides it the two arguments it needs.
Alternatively, you could just use a lambda expression:
MethodInvoker invoker = () => UpdateListBox(line, addEmptyRow);
lboImages.Invoke(invoker);

Pass reflected method as parameter to another reflected method as delegate

I have a function with a signature like so
private void FunkA(string eventName, Action action) {}
private void FunkB() {}
that I obtain though reflection. The value for action is also obtained through reflection so in my code I end up having to find a way to pass a 'MethodInfo' as a parameter into an invoke.
MethodInfo miForFunkA;
MethodInfo miForFunkB;
miForFunkA.Invoke(sourceOfFunkA, new [] {
methodInfo.Name,
Delegate.CreateDelegate(typeof(Action), miForFunkB)
});
The issue is I cant create a parameter list that has string and delegate types.
How should this be passed?
You should be to specify the array type explicitly:
miForFunkA.Invoke(sourceOfFunkA, new object[] {
methodInfo.Name,
Delegate.CreateDelegate(typeof(Action), miForFunkB)
});
If that doesn't address your question, you should edit your question so that it's clearer about what you're trying to do, declarations of all variables involved, what code you have now, what it does, and how that's different from what you want to do.

C# DynamicInvoke TargetParameterCountException

i've been searching a while now but i haven't found a solution for my Problem. I've got a class that stacks methods on a list and then calls them one by one.
Everything works fine with return values, Parameters or methods without Parameters. But if a method has a optional Parameter it doesn't work.
This is just a simple testing method:
static void TestMe(Int32 _wait = 5000)
{
//Pretend to do stuff...
System.Threading.Thread.Sleep(_wait);
}
I add the method to my stack with:
static StackHandler __handler = new StackHandler();
__handler.AddMethod(new Action<Int32>(TestMe));
The AddMethod method creates a new ListItem and adds it into an internal list to Keep track of all stacked methods.
Then the handler wants to call the method with:
private object invokeMethod(Delegate _method, params object[] _args)
{
return _method.DynamicInvoke(_args);
}
I get a System.Reflection.TargetParameterCountException in the invokeMethod method. I've also tried to call it without the args Parameter, same result.
If i add the method TestMe like this:
__handler.AddMethodAsync(new Action<Int32>(Method), 6000);
It just runs fine.
How can i get this to work with optional Parameters?

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

Say I have a method:
public void SomeMethod(String p1, String p2, int p3)
{
#if DEBUG
object[] args = GetArguments();
LogParamaters(args);
#endif
// Do Normal stuff in the method
}
Is there a way to retrieve an array of the arguments passed into the method, so that they can be logged?
I have a large number of methods and want to avoid manually passing the arguments by name to the logger, as human error will inevitably creep in.
I'm guessing it will involve reflection in some form - which is fine, as it will only be used for debugging purposes.
Update
A little more information:
I can't change the method signature of SomeMethod, as it is exposed as a WebMethod and has to replicate the legacy system it is impersonating.
The legacy system already logs the arguments that are passed in. To start with the new implementation will wrap the legacy system, so I'm looking to log the parameters coming into the C# version, so that I can verify the right parameters are passed in in the right order.
I'm just looking to log the argument values and order, not their names.
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)
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)
{
//..
}
Well, if you just want to pass the values, you can cheat and define an object array:
public static void LogParameters(params object[] vals)
{
}
This will incur boxing on value types and also not give you any parameter names, however.
Say I have a method:
public void SomeMethod(String p1, String p2, int p3)
{
#if DEBUG
LogParamaters(p1, p2, p3);
#endif
// Do Normal stuff in the method
}
Update: unfortunately reflection will not do it all automatically for you. You will need to provide the values, but you can use reflection to provide the param names/types:
How can you get the names of method parameters?
So the method sig would change to something like:
public static void LogParameters(string[] methodNames, params object[] vals)
{ }
Then you can enforce/assume that each index in each collection tallies, such that methodNames[0] has the value vals[0].
Well params help with the log call, but won't help the existing method signatures. Logging using an AOP framework might be a more productive approach?
Sure can ...check out this post, it gets the actual values of the params.
how to enumerate passed method parameters
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
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);
}
}
}
As long as you know what types to expect you could log them in an SQL database. Write a method that does a type check, and then fills the appropriate DB column with the parameter (argument) value. If you have a custom type then you can use the type name and save that as string in it's own special column.
-Edit
Also, using the MethodBase.Name extension method, you could associate your parameters with the method that took them as arguments as mentioned in another post below. Be a handy way of keeping track of all methods used, and with which arguments, and of which type.
Is this even vaguely a good idea? :)
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.

How to receive an argument in console program?

So I want other users to be able to run my programm sending arguments. how to do such thing?
If you have a Main method (which you'll have with a command-line app) you can access them directly as the args string-array parameter.
public static void Main(string[] args) {
var arg1 = args[0];
var arg2 = args[1];
}
If you're some other place in your code you can access the static Environment.GetCommandLineArgs method
//somewhere in your code
var args = Environment.GetCommandLineArgs();
var arg1 = args[0];
var arg2 = args[1];
You mean args when launching? such as myapp.exe blah blah2 blah3
Make your main method look like this:
public static void Main(string[] args)
{
}
now args is an array of the arguments passed into the program. So in the example case, args[0] == "blah", args[1] == "blah2", etc
The program is run from a method with this signature
public static void Main(string[] args)
The parameter args will contain the command line arguments, split on space.
While string[] args works just fine, it's worth mentioning Environment.GetCommandLineArgs.
You can read command line arguments from Main's optional string[] parameter:
static void Main(string[] args)
{
if (args.Length >= 1)
{
string x = args[0];
// etc...
}
}
Note that the following declaration for the Main method is also valid, but then you don't have access to the command line arguments:
static void Main()
{
// ...
}
See the documentation for more details.
This is supported by default, and the arguments will appear in the args array passed to your program.
public static void Main(string[] args)
If you say
App.exe Hello World What's Up
On a command line, you will receive an args array like this:
[0] = "Hello"
[1] = "World"
[2] = "What's"
[3] = "Up"
It's just up to you to determine what arguments you want, how they will be formatted, etc.
try these:
http://sourceforge.net/projects/csharpoptparse/
http://www.codeproject.com/KB/recipes/command_line.aspx
they basically allow you to define args and parse them in an OO way rather than having to lots of string comparisons and stuff like that. i used a similar one for java and it was great

Categories