NSouth
NSouth

Reputation: 5276

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>

Upvotes: 0

Views: 74

Answers (2)

Gus
Gus

Reputation: 3554

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

Upvotes: 0

Chris Pratt
Chris Pratt

Reputation: 239450

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.

Upvotes: 1

Related Questions