How to get the methodname from a known method? - c#

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";
}

Related

Can I take a method identifier (ex: MyClass.MyMethod) as a method parameter in C#?

The way nameof() works, I can write
var s = nameof(HomeController.Index);
Can I make my own compile-time method that works the same way and can take the same input? For example:
public static string MyMethod(Something input) // I'm not sure what Something should be
{
// do something with input to get method info
}
... // elsewhere in code
var s = MyMethod(HomeController.Index);
Update for context:
More specifically I would like to be able to make a helper method to be used in a Razor view. For example, I might call MyMethod(HomeController.Index) to return a string listing the controller name and the action name. It would be nice to be able to make such a method without having to pass both the controller type HomeController and the method name Invoke as separate parameters.
Update for more context and example:
My goal is to avoid magic strings when specifying controllers and actions in Razor views. Here's an example of how I am doing this currently by checking for the [Action] attribute on actions and trimming of the "Controller" suffix from controllers. But you can see that it's verbose.
<a asp-action="#(ControllerHelpers.GetActionName<HomeController>(nameof(HomeController.Index)))" asp-controller="#(ControllerHelpers.GetRouteName<HomeController>())">Link to Home</a>
I'm looking for a way to do something like this
<a asp-action="#ControllerHelpers.GetActionName(HomeController.Index)" asp-controller="#(ControllerHelpers.GetRouteName<HomeController>())">Link to Home</a>
and perhaps eventually my own tag helper like this. But even here I'd like to avoid having to separately pass both the controller and the action name (just for concision).
<a asp-controller-action="HomeController.Index">Link to Home</a>
You can do this via reflection, passing the method name as a string, and then using Type.GetMethod to get the method and then call Invoke on that, with the type instance.
However, the better thing to do here is to use a delegate. Specifically, you can do something like:
public static string MyMethod(Func<IActionResult> func)
And then:
var s = MyMethod(() => controller.Index());
Inside MyMethod, you'd invoke this like any other method, i.e. func().
That said, what you're trying to ultimately achieve here is unclear and suspect. You can't just invoke HomeController.Index; you need a HomeController instance. Manually newing up a controller, is pretty much always wrong, so there's probably a better way to achieve what you want, in general.
In other words, you seem to have an XY problem here. You're trying to do X, and you've decided Y is the way to do that (here, trying to pass a method reference and invoke that for some reason). But, you don't know how to do Y, either. Instead of asking about X, i.e. the thing you actually need help with, you're asking about Y, which almost assuredly isn't even a good way to do X, in the first place. Give us some more info on X, the thing you actually want, and we can probably give you a better method to achieve that.
I'm not 100% sure what you're asking for, but here's an example of how to do something like what you're asking for using delegates (MS delegate guide):
class MethodRunner
{
// use delegates to define the method signature that you'll operate on
public delegate void NoArgFormat();
public delegate void OneStringArgFormat(String arg);
//You can accept delegates as function arguments, then call them
//with a "live" object instance
public void RunMyMehtod(NoArgFormat methodToRun)
{
methodToRun();//runs the methd passed in
}
public void RunMyStringArgMethod(OneStringArgFormat methodToRun, String arg)
{
methodToRun(arg);
}
}
class Program
{
//This matches to "NoArgFormat" delegate definition
public void Method1()
{
Console.WriteLine("Method1");
}
//This matches the OneStringArgFormat
public void Method2(String arg)
{
Console.WriteLine(arg);
}
static void Main(string[] args)
{
Program p = new Program();
MethodRunner mr = new MethodRunner();
mr.RunMyMehtod(p.Method1);
mr.RunMyStringArgMethod(p.Method2, "First");
mr.RunMyStringArgMethod(p.Method2, "Second");
}
}
Sample output:
C:\Workspace\SampleApp\bin\Debug>SampleApp.exe
Method1
First
Second

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);

Pass member name as argument

Is possible pass only the name of method / function (member) without parameters?
Something similar to what Moq does:
Mock<Foo>fooMoq = new Mock<Foo>();
fooMoq.Setup(f => f.DummyMethod(It.IsAny<string>()));
but, without It.IsAny ():
Mock<Foo> fooMoq = new Mock<Foo>();
fooMoq.Setup(f => f.DummyMethod);
I don't mean in the context of Moq, but in general.
Thanks.
Edit:
I want to obtain is the name of the member, to later intercept calls to that method. That's why I'm not interested in knowing what parameters will be passed to the method, I just want to know what methods they want to intercept.
No you can't pass method from an instance of lambda parameter. The closest you can get is to use method group conversion. However you didn't really specify what you want to achieve.
After OP edit:
There is no easier way to do it, that's why popular frameworks like MOQ requires from you to pass all required parameters. One of common ways of doing this is just pass a method with only nulls (or default values for value types) like this:
fooMoq.Setup(f => f.DummyMethod(null,null,null));
There is also one more approach which allow you to not pass any parameters but you lose static type check for the type of a method so you can pass any method name there. Also reading it will be more problematic because you'll only have method name and type which can cause issues when reading overloaded functions.
public class Program
{
public static void Main()
{
Setup<Test>(nameof(Test.DummyMethod));
}
public static void Setup<T>(string methodName)
{
}
}
public class Test
{
public void DummyMethod()
{
}
}

How to use C# attributes to select a method in a class based on a string?

Suppose I have a class like this:
public class MyMethods
{
[SpecialMethod("test")]
public string GetTestString(int i)
{
return string.Format("Hello world {0} times!",i);
}
[SpecialMethod("lorem")]
public string GetSomeLoremIpsumText(int i)
{
// ignores the 'i' variable
return "Lorem ipsum dolor sit amet";
}
// ... more methods with the same signature here ...
public string DefaultMethod(int i)
{
return "The default method happened! The attribute wasn't found.";
}
public string ThisMethodShouldNotShowUpViaAttributes(int i)
{
return "You should not be here.";
}
}
I also have defined the attribute simply like this:
[AttributeUsage(AttributeTargets.Method)]
public class SpecialMethodAttribute : System.Attribute
{
private string _accessor;
public string Accessor
{
get
{
return _accessor;
}
}
public SpecialMethodAttribute(string accessor)
{
_accessor = accessor;
}
}
What I want to be able to do might look like this:
public class MethodAccessViaAttribute
{
private MyMethods _m;
public MethodAccessViaAttribute()
{
_m = new MyMethods();
}
public string CallMethodByAccessor(string accessor, int i)
{
// this is pseudo-code, expressing what I want to be able to do.
Func<int, string> methodToCall = FindAMethodByAttribute(_m, accessor);
if (methodToCall == null)
return _m.DefaultMethod(i);
else
return methodToCall(i);
}
public void Test()
{
// should print "Hello world 3 times!"
Console.WriteLine(CallMethodByAccessor("test",3));
// should print "Lorem ipsum dolor sit amet"
Console.WriteLine(CallMethodByAccessor("lorem",int.MaxValue));
// should print "The default method happened! The attribute wasn't found."
Console.WriteLine(CallMethodByAccessor("I-do-not-exist",0));
}
}
Notice that all methods using the SpecialMethod attribute follow the same method signature. Ideally, the search function would exclude methods not matching the signature, since a try/catch could be used to test if the method matches the Func signature.
Can I get a point in the right direction for how to accomplish this?
I don't like giving "do this instead" answers, but I can't put this inside a comment.
Instead of this, along with all of the supporting code to handle the attributes
public void Test()
{
Console.WriteLine(CallMethodByAccessor("test",3));
Console.WriteLine(CallMethodByAccessor("lorem",int.MaxValue));
Console.WriteLine(CallMethodByAccessor("I-do-not-exist",0));
}
This code does the exact same thing:
public void Test()
{
var methods = new MyMethods();
Console.WriteLine(methods.GetTestString("test", 3));
Console.WriteLine(methods.GetSomeLoremIpsumText("lorem", int.MaxValue));
}
The language is designed on purpose so that if a method doesn't exist, you can't call it. That helps us avoid mistakes at runtime. We don't want our application to execute something or ignore it based on whether or not we spelled a method name correctly. Someone could pull their hair out for hours trying to figure out why the application isn't working and then realize that it's because they misspelled "lorem." Just calling methods the "normal" way prevents all of that. If you misspell a method name then Visual Studio will show an error, the code won't compile, and it's super easy to find and fix. (Plus Intellisense/autocomplete will even help us see the methods that are available.)
Also, if you right-click on a method then Visual Studio will take you right to that method. With the string attributes someone has to follow a lot more code just to figure out which method is actually getting called. And if they need to debug and step through it, they need to step through all that extra stuff.
It's extremely common to have a bunch of classes that each implement the same interface and each have one method. It's good design to have fewer methods - even one - in an interface. (See Interface Segregation Principle.) No one will consider that "ugly." But if we invent our own way of doing it we can really confuse other developers who work on the same code, and it can be challenging to maintain even for the person who wrote it.
So I did figure out how to accomplish this task.
I created a class which all classes that contain methods will inherit from. I then created a private method which actually extract and create Func objects.
We need a method which will search for any method that has the desired attribute. Reflection has a MethodInfo class which represents a method. We can use some LINQ to search all of the methods on the class. We then use a little expression tree fun to generate the Func object that will actually call the method on this specific instance of the class:
// Locates a method on this class that has the SpecialMethod attribute of the given name
private Func<int, string> FindMethodByAccessor(string accessor)
{
// Find all methods containing the attribute
var desiredMethod = this.GetType().GetMethods()
.Where(x => x.GetCustomAttributes(typeof(SpecialMethod), false).Length > 0)
.Where(y => (y.GetCustomAttributes(typeof(SpecialMethod), false).First() as SpecialMethod).Accessor == accessor)
.FirstOrDefault();
if (desiredMethod == null) return null;
// This parameter is the first parameter passed into the method. In this case it is an int.
ParameterExpression x = Expression.Parameter(typeof(int));
// This parameter refers to the instance of the class.
ConstantExpression instance = Expression.Constant(this);
// This generates a piece of code and returns it in a Func object. We effectively are simply calling the method.
return Expression.Lambda<Func<int, string>>(
Expression.Call(instance, desiredMethod, new Expression[] { x }), x).Compile();
}
The idea of expression trees is still new to me, but this function does exactly what I want - it will locate a method on the instance of the class it's running in which has been decorated with the given attribute and return it as a Func object.
We can now finish the method which actually calls the other methods:
public string CallMethodByAccessor(string accessor, int i)
{
Func<int, string> methodToCall = FindMethodByAccessor(accessor);
if (methodToCall == null)
return DefaultMethod(i);
else
return methodToCall(i);
}
public string DefaultMethod(int i) { return "Unknown method requested!"; }
I still have not added checking to see whether the method with the attribute matches the necessary signature, but that could easily be done by working with properties on the MethodInfo object.
Finally, we wrap all this up in a class, which any other class can inherit from. The subclass then implements methods following the signature and decorates them with the attribute. To call the desired method by name, you simply call CallMethodByAccessor.
To respond finally to all of the suggestions to use a different methodology, I respect all of your ideas and, if the use case were different, this would absolutely be overkill and unnecessary. The specific use case at hand involves a Web service which users and developers can configure. The Web service lets a user specify one or more "endpoints". The endpoint in this case is merely a string. The library I am writing receives data from the Web service, and one of the parameters is the desired "endpoint" string. The idea is that the user could write endpoints as methods, give them any function name they desire, and then associate them with the actual endpoint text via the attribute. For example:
[Endpoint("user.login")]
public string performLogin(string credentialString)
{
// ...
}
Since the endpoint name is user.login we cannot simply name a class method with that name. Additionally, even if we did, we would still need to use reflection to dig into the class, extract the correct method, and generate a Func object to call the method. So, in this instance, using attributes simply makes development far easier, because the only alternative would be using a switch/case block that would have to be rigorously maintained. I feel it would be far more easy for a developer to "forget" to add another case block, or to forget to remove a case block which is no longer needed, than it would be to mess up the attributes. The attribute "ties" the endpoint name to the method, rather than having to keep track of both the method name and the endpoint name in a totally different block of code.
Finally, the "default" method is absolutely useful in this case. If a user instructs the Web service to call an endpoint which doesn't exist, the app can return a sensible response, e.g. "The endpoint 'MyEendpoint' does not exist." This would be much easier to debug than simply seeing the API crash!

Putting function in appropriate class

public static FirstObjectType GetObject(SecondObjectType secondobjectType)
{
do something
}
Where should I put this function? Should I put it in SecondObjectType class or FirstObjectType class in terms of code readability, customs and traditions? Should the function be included in the return class or the parameter class from your experience?
Thanks for your answer.
I usually put the method in the class that has the same type as the return type of the method.
eg:
public static FirstObjectType GetObject(SecondObjectType secondobjectType)
{
do something
}
would go in the FirstObjectType class.
Alternatively you can use the Factory Pattern and have a factory for getting the objects you need. Which could give you code simliar to the following:
FirstObjectTypeFactory.GetObject(SecondObjectType secondObjectType)
Then you always know which factory to get the object from based on its return type.
This is way to vague to answer, but I'll give a few general tips
If you have a collection of FirstObjectTypes and are trying to find the one that matches SecondObjectType, then it belongs to the class that owns the collection. This could be a factory pattern.
If you are always creating a new FirstObjectType, it could just be a constructor for FirstObjectType.
Does SecondObjectType have to have knowledge of FirstObjectType? If so, then it I would consider making it a method on SecondObjectType.
There are a million other scenarios and there is no one size fits all.
I'll create an Extension Method for that.
Just add this in the signature
public static FirstObjectType GetObject(this SecondObjectType secondobjectType)
{
//do something
}
After that you can do:
SecondObjectType sobj = new SecondObjectType()
//code
FirstObjectType fobj = sobj.GetObject();
And put it with my other extension method file like ExtensionMethods.cs.
Or if the class containing the GetObject method is static too, put it in the same class (In this case in the SecondObjectType's class)

Categories

Resources