When I'm trying to use params in an Action delegate...
private Action<string, params object[]> WriteToLogCallBack;
I received this design time error:
Invalid token 'params' in class, struct, or interface member declaration
Any help!
How about this workaround?
private Action<string, object[]> writeToLogCallBack;
public void WriteToLogCallBack(string s, params object[] args)
{
if(writeToLogCallBack!=null)
writeToLogCallBack(s,args);
}
Or you could define your own delegate type:
delegate void LogAction(string s, params object[] args);
Variadic type parameters are not possible in C#.
That's why there're many declarations for Action<...>, Func<...>, and Tuple<...>, for example. It would be an interesting feature, though. C++0x has them.
You could try this. It allows for any number of arguments, and you'll get a compile time error if you pass the wrong number or type of arguments.
public delegate T ParamsAction<T>(params object[] oArgs);
public static T LogAction<T>(string s, ParamsAction<T> oCallback)
{
Log(s);
T result = oCallback();
return result;
}
Foo foo = LogAction<Foo>("Hello world.", aoArgs => GetFoo(1,"",'',1.1));
You can use params in the actual declaration of a delegate, but not in type of one. The generic parameters to an Action are only types, not the actual arguments to be passed when invoking the delegate. params is not a type, it is a keyword.
I have done a minor extension to the above code from Bryan, to show how to wrap multiple method calls.
I am using this to wrap multiple methods that contain database calls, into a single transaction.
Thanks Bryan :-)
(You can run the following in LINQPad to test)
//Wrapper code
public delegate void MyAction(params object[] objArgs);
public static void RunActions(params MyAction[] actnArgs)
{
Console.WriteLine("WrapperBefore: Begin transaction code\n");
actnArgs.ToList().ForEach( actn => actn() );
Console.WriteLine("\nWrapperAfter: Commit transaction code");
}
//Methods being called
public void Hash (string s, int i, int j) => Console.WriteLine(" Hash-method call: " + s + "###" + i.ToString() + j.ToString());
public void Slash (int i, string s) => Console.WriteLine(" Slash-method call: " + i.ToString()+ #"////" + s);
//Actual calling code
void Main()
{
RunActions( objArgs => Hash("One", 2, 1)
,objArgs => Slash(3, "four") );
}
//Resulting output:
//
// WrapperBefore: Begin transaction code
//
// Hash-method call: One###21
// Slash-method call: 3////four
//
// WrapperAfter: Commit transaction code
Related
I currently have a method like that resembles this
public static bool test(string str);
I would like to assign this method to this type
Func<bool> callback
I am trying to do this (which is incorrect)
callback = test("Str");
The above is incorrect as C# things i am calling a method. How can I tell it to call that method with the parameter Str ? in C++ we can do this
std::function<...,..,"str">
How do we do something similar in C# ?
If your goal is to invoke the callback always using the same string argument (and not a different argument each time), you can declare it like:
Func<bool> callback = () => test("Str");
var result = callback();
But if you are intending to pass a different string value each time, then you need a Func<string, bool>:
Func<string, bool> callback = s => test(s);
var result = callback("Str");
you should declare the function as:
Func<string, bool> callback
to indicate the method it references consumes a string and returns a bool.
then at a later point you can do:
callback = s => test(s);
or inline:
Func<string, bool> callback = s => test(s);
Let me see if I know what you're getting at. In C++ we have 'function pointers' and they are declared with a particular signature. To make the equivalent of that in C# use the delegate keyword.
Here's a quick functional code example:
class DelegateExample
{
// A delegate is a prototype for a function signature.
// Similar to a function pointer in C++.
delegate bool MyDelegate(string[] strings);
// A method that has that signature.
bool ListStrings(string[] strings)
{
foreach (var item in strings)
{
Console.WriteLine(item);
}
return strings.Length > 0; // ... for example
}
// Different method, same signature.
bool Join(string[] strings)
{
Console.WriteLine(string.Join(", ", strings));
return strings.Length > 0; // ... for example
}
public void TryIt()
{
string[] testData = { "Apple", "Orange", "Grape" };
// Think of this as a list of function pointers...
List<MyDelegate> functions = new List<MyDelegate>();
functions.Add(ListStrings); // This one points to the ListStrings method
functions.Add(Join); // This one points to the Join method
foreach (var function in functions)
{
bool returnVal = function(testData);
Console.WriteLine("The method returned " + returnVal + Environment.NewLine);
}
}
}
You can run the sample in a console app like so:
class Program
{
static void Main(string[] args)
{
new DelegateExample().TryIt();
Console.ReadKey();
}
}
Which gives this output:
Apple
Orange
Grape
The method returned True
Apple, Orange, Grape
The method returned True
Hope this is helpful!
I am writing a very simple scripting tool with my own functions.
I can invoke methods just fine with and without parameters. My main issue is parsing the parameters that the user input.
do I need to hardcore a parser myself or is there a better way to do so?
sample code
public class FunctionList
{
public void MyMethod(string x)
{
MessageBox.Show(x);
}
}
public void Test()
{
Type type = typeof(FunctionList);
MethodInfo method = type.GetMethod(debugBox.Text);
FunctionList c = new FunctionList();
method.Invoke(c, new object[] { "lorem ipsum" });
}
Example user input in TextBox:
MyMethod(Hello World)
Sleep(500)
MyMethod(Waited 500 ms)
Sum(5, 4)
I will also want to add in conditions and loops, but i think that would require something other then invoking methods.
Example of what i came up with as a parser:
public void Test()
{
Type type = typeof(FunctionList);
MethodInfo method = type.GetMethod(helper.GetUntilOrEmpty(debugBox.Text, "(")); //gets all text until first ( which translates to the function name
FunctionList c = new FunctionList();
//Handles one argument, gets the text between ( )
int pFrom = debugBox.Text.IndexOf("(") + "(".Length;
int pTo = debugBox.Text.LastIndexOf(")");
string result = debugBox.Text.Substring(pFrom, pTo - pFrom);
//pass params
method.Invoke(c, new object[] { result });
}
I have a lot of experience in dealing with such scenarios. I developed my own scripting engine (back in Adobe Flash golden age).
If you have a complex mechanism to create functions and objects than I will recommend you to write a parser that translates your custom scripting code into C#'s compile time error free code.
I have tested your code and it works fine if you already know which parameter you are gonna pass.
public void Test()
{
Type type = typeof(FunctionList);
MethodInfo method = type.GetMethod("MyMethod");
FunctionList c = new FunctionList();
// if you dont know the type of parameter passed then you have to write a parser to determine the type of the parameter right before executing the method.
method.Invoke(c, new object[] { "lorem ipsum" , 10});
}
}
public class FunctionList
{
public void MyMethod(string x, int y)
{
MessageBox.Show(x + " : " + y);
}
}
I need to create a CSV style string of parameters mapped to their values.
For example:
static void MyMethod(int i, string str, object obj, bool flag)
{
string example = "i=123,str=Hello,obj=1.0,flag=false";
}
Called like:
MyMethod(123, "Hello", 1.0, false);
I would want an output like the string example.
I need to do this for a large number of methods which have many different signatures and may not use all parameters in each method with no discernible pattern - so I have tried to create a method to automate the process somewhat.
I have attempted to solve this using a delegate and nameof:
delegate string GetParametersDelegate(params object[] parameters);
static GetParametersDelegate GetParametersFunc = (parameters) =>
{
return string.Join(",", parameters
.Select(parameter => nameof(parameter) + "=" + parameter));
};
Called like:
static void MyMethod(int i, string str, object obj, bool flag)
{
string notTheResultIWant = GetParameters(i, str, obj, flag);
// notTheResultIWant = "parameter=123,parameter=Hello,parameter=1.0,parameter=false"
}
I have found this results in the name of the variable in the lambda being used instead of the original parameter name - so every value is incorrectly mapped to parameter from the lambda.
Is what I'm trying to do even possible to achieve? Or is there another way I can approach this problem?
One solution I came up with is getting ParameterInfo[] of called method via its MethodInfo:
delegate string GetParametersDelegate(Delegate method, params object[] parameters);
static GetParametersDelegate GetParametersFunc = (method, parameters) =>
{
var paramNames = method.Method.GetParameters().Select(pInfo => pInfo.Name);
return
paramNames.Select((name, index) => $"{name}={parameters[index]?.ToString() ?? "null"}")
.Aggregate((a, b) => $"{a},{b}");
};
You can call:
static void MyMethod(int i, string str, object obj, bool flag)
{
var method = (Action<int, string, object, bool>)MyMethod;
var notTheResultIWant = GetParametersFunc(method, i, str, obj, flag);
}
I have the following code:
Func<string, string> func1 = (param) =>
{
Console.WriteLine("Func 1 executing");
return "Hello" + param;
};
Func<string, string> func2 = (param) =>
{
Console.WriteLine("Func 2 executing");
return "World" + param;
};
Func<string, string> funcSum = func1 + func2;
string funcResult = funcSum("!");
Console.WriteLine(funcResult);
The output is:
Func 1 executing
Func 2 executing
World!
Inverting the sum:
Func<string, string> funcSum = func2 + func1;
Gives the output:
Func 2 executing
Func 1 executing
Hello!
My initial test was done with a boolean return type, and the returned value was also always determined by the last function. Is it working as intended? Aren't we losing the return value of the other functions? If so, is there a use case in real world of those multicast delegate of functions?
Is it working as intended?
It's working as specified, at least. Whether that's what you intended or not is a different matter :) From section 15.4 of the C# 5 specification - emphasis mine:
Invocation of a delegate instance whose invocation list contains multiple entries proceeds by invoking each of the methods in the invocation list, synchronously, in order. Each method so called is passed the same set of arguments as was given to the delegate instance. If such a delegate invocation includes reference parameters (ยง10.6.1.2), each method invocation will occur with a reference to the same variable; changes to that variable by one method in the invocation list will be visible to methods further down the invocation list. If the delegate invocation includes output parameters or a return value, their final value will come from the invocation of the last delegate in the list.
Next:
Aren't we losing the return value of the other functions?
Yes, at the moment.
If so, is there a use case in real world of those multicast delegate of functions?
Very rarely, to be honest. However, you can split a multicast delegate apart, using Delegate.GetInvocationList():
foreach (Func<string, string> func in funcSum.GetInvocationList())
{
Console.WriteLine(func("!"));
}
Most of your question has been answered already, but one thing that's missing is a real-world use case for this. Here's one: asynchronous event handlers.
public delegate Task AsyncEventHandler(object sender, EventArgs e);
public event AsyncEventHandler X;
public async Task OnX(EventArgs e) {
// ...
var #event = X;
if (#event != null)
await Task.WhenAll(
Array.ConvertAll(
#event.GetInvocationList(),
d => ((AsyncEventHandler)d)(this, e)));
}
This allows the user of the class to simply write
myobject.X += async (sender, e) => { ... };
but the object will still ensure that OnX's task doesn't complete until the event handler's has.
The multicast delegate will always return the result of the last function. Because there is no predefined way to combine or chain the T results.
If you want to obtain all the results along the chain, try this :
var result = "!";
foreach (Func<string, string> func in funcSum.GetInvocationList())
{
result = func(result);
}
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.)
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.
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
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")
{
}
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.
It is not possible, and I wonder why you would need that.
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!
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.
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.