Get Name of Action/Func Delegate - c#

I have a weird situation where I need to get the Name of the delegate as a string. I have a generic method that looks like this.
private T Get<T>(T task, Action<T> method) where T : class
{
string methodName = method.Method.Name //Should return Bark
}
and I am calling it like this
private void MakeDogBark()
{
dog = Get(dog, x=>x.Bark());
}
But instead of seeing "Bark" I see this "<MakeDogBark>b__19". So it looks like it is giving me the method name that made the initial call instead of the name of the delegate.
Anyone know how to do this?

It's giving you the name of the method which is the action of the delegate. That just happens to be implemented using a lambda expression.
You've currently got a delegate which in turn calls Bark. If you want to use Bark directly, you'll need to create an open delegate for the Bark method, which may not be terribly straightforward. That's assuming you actually want to call it. If you don't need to call it, or you know that it will be called on the first argument anyway, you could use:
private T Get<T>(T task, Action method) where T : class
{
string methodName = method.Method.Name //Should return Bark
}
private void MakeDogBark()
{
dog = Get(dog, dog.Bark);
}
You could get round this by making the parameter an expression tree instead of a delegate, but then it would only work if the lambda expression were just a method call anyway.

You can get the name of the method call by making the parameter an expression instead of a delegate, just like Jon mentioned
private T Get<T>(T task, Expression<Action<T>> method) where T : class
{
if (method.Body.NodeType == ExpressionType.Call)
{
var info = (MethodCallExpression)method.Body;
var name = info.Method.Name; // Will return "Bark"
}
//.....
}

Related

C# delegate properties

Is it possible to pass a property as a delegate in c#?
I know that in C# we can pass functions as arguments to a method, But I have a property which in my situation is not much different than a function that takes no parameters, how can I pass it as an argument?
public IWebElement Name => _element.FindElements(By.ClassName("field-key"))[0].FindElements(By.TagName("label"))[0];
I'm working with selenium and changing elements. That's the reason why my Name property is the way it is. So I always get the latest name when I do something like: MultinationalPage.GeneralPanel.DefinitionField.Name.
In my test to prevent getting Stale Element Reference Exception, I use Thread.Sleep(), I know there are better ways, however, for now, this is my approach.
Thread.Sleep(5000)
multinational.EditModal.StateTracker.VerifyChanges(_multinational.GeneralPanel.DefinitionField.Name);
I would like to do the Thread.Sleep(5000) inside the VerifyChanges() that's why I want to pass the Name property as a delegate to VerifyChanges(MultinationalPage.GeneralPanel.DefinitionField.Name).
Something like this:
public void VerifyChanges(Func<IWebElement> Name)
{
Thread.Sleep(5000)
var name = Name;
...
}
I think there is a better way to solve this problem.
Create an interface:
interface IHasName
{
IWebElement Name { get; }
}
Implement:
class YourClass : IHasName
{
public IWebElement Name
=> _element.FindElements(By.ClassName("field-key"))[0].FindElements(By.TagName("label"))[0];
}
Then your method:
public void VerifyChanges(IHasName hasName)
{
Thread.Sleep(5000)
var name = hasName.Name;
...
}
A solution is to encapsulate the access to property in a lambda :
multinational.EditModal.StateTracker.VerifyChanges(
() => _multinational.GeneralPanel.DefinitionField.Name
);
If you can share your full code then we can have a better understanding of the problem that you are trying to solve. Passing a property is the same as passing a parameter value to a function. e.g. Lets us assume your function looks like
public void MyFunction(IWebElement webElement)
{
// Your code goes here.
}
You can call this function and pass the property as follows:
MyClass obj = new MyClass();
MyFunction(obj.Name);
I assumed that MyClass is the name of the class which has this property.
======== Edited
In you case you can wrap your code inside a Func as follows
public void VerifyChanges(() => multinational.GeneralPanel.DefinitionField.Name);

c# - call a specific method when signatures are the same

I'm not sure exactly how to call this situation, but here it is:
I have 2 methods with different types, but from the "outside" they have the same signature. And when calling the method, I would like to invoke a specific method instead of the other - here is what I have:
public class SomeClass
{
public async Task<Response<T>> MyMethod<T>(string name, T myObj)
{
// some code here
}
public async Task<Response<T>> MyMethod<T>(string name, string myObj)
{
// some code here
}
}
For the compiler, the 2 methods above are different and have different signatures. But when calling:
var myClass = new SomeClass();
myClass.MyMethod("name", "something");
When calling MyMethod in the example, what's being called is MyMethod<T>(string name, T myObj), but what I would actually want to call is the second method. Is there a way to make it call a specific signature?
EDIT:
I found the if I give in one of the methods a different name to the second variable and then calling the method with the variable name as part of the call it does work, as in the following example:
public class SomeClass
{
public async Task<Response<T>> MyMethod<T>(string name, T myObj)
{
// some code here
}
public async Task<Response<T>> MyMethod<T>(string name, string myNewObj)
{
// some code here
}
}
var myClass = new SomeClass();
myClass.MyMethod<AnyOfMyTypes>("name", myNewObj: "something");
While this works, following Jon's response below, does it seem like something that is correct to do? As far as for the method name, I would like to keep it the same, and the other option is to change the signature by adding some dummy boolean variable.
The compiler certainly can't call the second method with that calling code, as it wouldn't know what to infer for T. If you specify a type argument though, it does call the second method:
myClass.MyMethod<string>("name", "something");
While that will work, I would strongly advise you to change the design if you possibly can. Rename one of the methods. I can reasonably call myself a C# expert, but I couldn't predict from inspection whether or not that would work. The overload resolution and type inference details in C# are really complicated, and it's unreasonable to expect every C# developer to know them inside out.
If you can give the methods different names, the code code is likely to be a lot simpler to read.
Following Jon's answer I'd suggest following solution to your problem:
private async Task<Response<T>> MethodForString<T>(string str)
{
// some code...
}
public async Task<Response<T>> Method<T>(T obj)
{
if (typeof(T) == typeof(string))
return MethodForString<T>(obj as string);
// some code...
}
Above is just a sample, but idea is simple: just check type of T and call appropriate method :)
This way, all your method call will remain exactly the same :)
The reason the first method is being called is because you have a generic type of T.
If you pass a string into this then it will hit the first method. It is better design to only have one method. If you want to be able to pass in any type then keep the first method, if you want just a string then keep just the second method. You should only have two methods if both have distinct clear purposes.
This
public class SomeClass
{
public async Task<Response<T>> MyMethod<T>(string name, T myObj)
{
// some code here
}
}
Or
public class SomeClass
{
public async Task<Response<T>> MyMethod<T>(string name, string myObj)
{
// some code here
}
}
Or
public class SomeClass
{
public async Task<Response<T>> MyMethod<T>(string name, string myObj)
{
// some code here
}
public async Task<Response<T>> MyMethod<T>(string name, int age, string address)
{
// some code here
}
}
Dont put a dummy variable into any of the methods, this will lead to problems debugging and be misleading for other developers.

How to get the methodname from a known method?

Is it possible to get the name of another method in the same class but without using a manually written string?
class MyClass {
private void doThis()
{
// Wanted something like this
print(otherMethod.name.ToString());
}
private void otherMethod()
{
}
}
You may ask why: well the reason is that I must invoke the method later on like this Invoke("otherMethod"), however I don't want to hardcode this string myself as I can't refactor it anymore within the project.
One approach is you can wrap it into delegate Action, then you can access the name of method:
string name = new Action(otherMethod).Method.Name;
You can use reflection (example - http://www.csharp-examples.net/get-method-names/) to get the method names. You can then look for the method that you're looking for by name, parameters or even use an attribute to tag it.
But the real question is - are you sure this is what you need? This looks as if you don't really need reflection, but need to think over your design. If you already know what method you're going to invoke, why do you need the name? How about a using a delegate? Or exposing the method via an interface and storing a reference to some class implementing it?
Try this:
MethodInfo method = this.GetType().GetMethod("otherMethod");
object result = method.Invoke(this, new object[] { });
Btw. I also found (in the expansions of the internet) an alternative solution for only getting the string of a method. It also works with parameters and return types:
System.Func<float, string> sysFunc = this.MyFunction;
string s = sysFunc.Method.Name; // prints "MyFunction"
public string MyFunction(float number)
{
return "hello world";
}

What is the purpose of delegates in .NET

So I'm a little bit confused about delegates in C#.... what do they do and how are they useful? I've read a few tutorials, and I don't really get exactly what they're supposed to do (everyone relates them to function pointers in C, and I've never programmed in C).
So... what do delegates do? What's a scenario in which I should use them? How would I then use them?
The other answers are good, but here's another way to think about delegates that might help. Imagine that a delegate is nothing more than an interface. When you see:
delegate void Action();
think:
interface IAction
{
void Invoke();
}
And when you see:
Action myAction = foo.Bar;
think:
class FooBarAction : IAction
{
public Foo Receiver { get; private set; }
public FooBarAction(Foo foo)
{
this.Receiver = foo;
}
public void Invoke()
{
this.Receiver.Bar();
}
}
...
IAction myAction = new FooBarAction(foo);
And when you see
myAction();
think
myAction.Invoke();
The actual details of what types get constructed are a bit different, but fundamentally that's what's happening. A delegate is simply an object with a method called Invoke, and when you call that method, it calls some other method on some other object on your behalf. That's why it's called a "delegate" -- because it delegates the call to another method of another object.
Delegates are sort of like objects that represent a method call. One useful way they can be used are as callbacks. For example, imagine you have a method that does something asynchronous, and you want the caller to be able to specify what they want to happen once it completes (Action is a type of delegate):
public void DoSomething(Action whatToDoWhenDone)
{
// Your code
// See how the delegate is called like a method
whatToDoWhenDone();
}
A user of DoSomething can now specify the callback as a parameter:
public void AnotherMethod()
{
DoSomething(ShowSuccess); // ShowSuccess will be called when done
}
public void ShowSuccess()
{
Console.WriteLine("Success!");
}
You can also use lamba expressions as a shorter way of writing your delegate:
public void AnotherMethod()
{
DoSomething(() => Console.WriteLine("Success!"));
// Also DoSomething(delegate() { Console.WriteLine("Success!"); });
}
Callbacks are far from the only use cases for delegates. Hopefully this shows you some of their power: the ability to have code to be executed as a variable.
Delegates allow you to treat functions as if they were any other variable. A delegate type defines the signature of the function, that is, what the function returns, and the number and type of arguments that it takes:
// This is the delegate for a function that takes a string and returns a string.
// It can also be written using the framework-provided Generic delegate Func, as
// Func<String, String>
delegate String StringToStringDelegate(String input);
You can define a variable of this type, and assign it to an existing method. I use the generic as an example, because that is the more common usage in .net since 2.0:
String Reverse(String input) {
return input.Reverse();
}
Func<String, String> someStringMethod = new Func<String, String>(Reverse);
// Prints "cba":
Console.WriteLine(someStringMethod("abc"));
You can also pass functions around this way:
String Reverse(String input) {
return input.Reverse();
}
String UpperCase(String input) {
return input.ToUpper();
}
String DoSomethingToABC(Func<String, String> inputFunction) {
return inputFunction("abc");
}
var someStringMethod = new Func<String, String>(Reverse);
// Prints "cba":
Console.WriteLine(DoSomethingToABC(someStringMethod));
var someOtherStringMethod = new Func<String, String>(UpperCase);
// Prints "ABC":
Console.WriteLine(DoSomethingToABC(someOtherStringMethod));
In a big application it is often required to other parts of the application based on some condition or something else. The delegate specifies the address of the method to be called. In simple manner a normal event handler implements the delegates in the inner layers.
The oversimplified answer is that a delegate is basically a "pointer" to a block of code, and the benefit is that you can pass this block of code into other functions by assigning your block of code to a variable.
The reason people relate Delegates to C function pointers is because this is in essence what delegation is all about, I.e.: Pointers to methods.
As an example:
public void DoSomething(Action yourCodeBlock)
{
yourCodeBlock();
}
public void CallingMethod()
{
this.DoSomething(
{
... statements
});
this.DoSomething(
{
... other statements
});
}
There are naturally lots of ways to invoke delegates as all of the tutorials will show you. The point is though that it allows you to "delegate" functionality in such a way that you can call into methods without necessarily knowing how they work, but simply trusting that they will be taken care of. In other words, I might create a class that implements a "DoSomething()" function, but I can leave it up to someone else to decide what DoSomething() will do later on.
I hope that helps. :-)
Delegates are a way to call back into your code when a long running operation completes or when an event occurs. For example, you pass a delegate to a method that asynchronously downloads a file in the background. When the download is complete, your delegate method would be invoked and it could then take some action such as processing the file's contents.
An event handler is a special type of delegate. For example, an event handler delegate can respond to an event like a mouse click or key press. Events are by far the most common type of delegate. In fact, you will typically see the event keyword used far more often in C# code than the delegate keyword.
You can think of it as a type in which you may store references to functions. That way you can in effect, store a function in a variable so you may call it later like any other function.
e.g.,
public delegate void AnEmptyVoidFunction();
This creates a delegate type called AnEmptyVoidFunction and it may be used to store references to functions that return void and has no arguments.
You could then store a reference to a function with that signature.
public static void SomeMethod() { }
public static int ADifferentMethod(int someArg) { return someArg; }
AnEmptyVoidFunction func1 = new AnEmptyVoidFunction(SomeMethod);
// or leave out the constructor call to let the compiler figure it out
AnEmptyVoidFunction func2 = SomeMethod;
// note that the above only works if it is a function defined
// within a class, it doesn't work with other delegates
//AnEmptyVoidFunction func3 = new AnEmptyVoidFunction(ADifferentMethod);
// error wrong function type
Not only can it store declared functions but also anonymous functions (i.e., lambdas or anonymous delegates)
// storing a lambda function (C#3 and up)
AnEmptyVoidFunction func4 = () => { };
// storing an anonymous delegate (C#2)
AnEmptyVoidFunction func5 = delegate() { };
To call these delegates, you can just invoke them like any other function call. Though since it is a variable, you may want to check if it is null beforehand.
AnEmptyVoidFunction func1 = () =>
{
Console.WriteLine("Hello World");
};
func1(); // "Hello World"
AnEmptyVoidFunction func2 = null;
func2(); // NullReferenceException
public static void CallIt(AnEmptyDelegate func)
{
// check first if it is not null
if (func != null)
{
func();
}
}
You would use them any time you needed to pass around a method that you wish to invoke. Almost in the same way that you may pass instances of objects so you may do what you wish with them. The typical use case for delegates is when declaring events. I have written another answer describing the pattern so you can look at that for more information on how to write those.

Argument type 'void' is not assignable to parameter type 'System.Action'

This is my test code:
class PassingInActionStatement
{
static void Main(string[] args)
{
var dsufac = new DoSomethingUsefulForAChange();
dsufac.Do(WriteToConsole);
dsufac.Do2(s => WriteToConsoleWithSomethingExtra("Test"));
dsufac.Do(WriteToConsoleWithSomethingExtra("Test")); // Does not compile
}
internal static void WriteToConsole()
{
Console.WriteLine("Done");
}
internal static void WriteToConsoleWithSomethingExtra(String input)
{
Console.WriteLine(input);
}
}
internal class DoSomethingUsefulForAChange
{
internal void Do(Action action)
{
action();
}
internal void Do2(Action<String> action)
{
action("");
}
}
The first 2 calls work but I am wondering why the 3rd one does not. I do not fancy the code inside Do2 as it seems strange that I have type type action("") in there in order to get it to work.
Could someone please explain the 2 things I do not understand please?
Why I can not write the third line like that with calling Do
Why I have to write action("") in order get it to work in Do2
dsufac.Do(WriteToConsoleWithSomethingExtra("Test"));
actually calls the function first (WriteToConsoleWithSomethingExtra("Test")) and then attempts to pass the result into Do. Since there is no result (void), it's not possible.
What you actually want is this:
dsufac.Do(() => WriteToConsoleWithSomethingExtra("Test"));
The inner part declares a function that takes nothing (the () => bit), which calls WriteToConsoleWithSomethingExtra("Test") when executed. Then your dsufac.Do call will receive an action, like it expects.
As for Do2 - you've declared it as taking Action<String>, which means that action is a function that takes one argument. You have to pass it a string. That string might be empty, like in your action("") example, or it might be passed in externally, as in something like this:
dsufac.Do3(WriteToConsole, "Test");
...
internal void Do3(Action<String> action, String str)
{
action(str);
}
In your code
dsufac.Do(WriteToConsoleWithSomethingExtra("Test"));
is interpreted like the following
var variable = WriteToConsoleWithSomethingExtra("Test");
dsufac.Do(variable);
As the return type of WriteToConsoleWithSomethingExtra("Test") is void, so you can not actually pass it to dsufac.Do(). That is why its not getting compiled. But for the first one
dsufac.Do(WriteToConsole);
you are not calling the function, rather you are passing it as a method group, which is later get invoked in the Do() method of dsufac object. But if you want to write the 3rd line as the 1st one, you can use
dsufac.Do(() => WriteToConsoleWithSomethingExtra("Test"));
Do expects an Action (i.e. method which take no parameters and returns no value). Hence WriteToConsoleWithSomethingExtra is not a valid fit - takes one string parameter.
Do2 accepts an Action<T> (i.e. method which takes in one T parameter and returns no value). Hence when you invoke the delegate/action you need to supply one parameter of type T, here String.

Categories

Resources