简体   繁体   中英

Is there a typed way to declare a method name in C#

I have some reflection code and I would love to have a way of binding the method names to types instead of declaring through strings.

I have this interface:

interface IDoStuff<T> {
    void Do(T stuff);
}

Then I have this code:

object stuff = GotThisFromSomewhereElse();
object doer = GotThisFromSomewhereElseAlso();
var doMethodInfo = doer.GetType().GetMethod("Do");
doMethodInfo.Invoke(doer, new[] { stuff });

The problem is that I can't simply do a safe cast and call it because it's generic and I don't actually know what type T is.

This works fine but when I rename the method I have to go update this, I'm not overly concerned as I have tests to confirm all of this works which protects against not knowing it changed.

It's just really ugly and I was curious if there is some slick way to have this typed and thus will get renamed by ReSharper if I change it.

I'd really like something like:

object stuff = GotThisFromSomewhereElse();
object doer = GotThisFromSomewhereElseAlso();
var doMethodInfo = doer.GetType().Methods.Do;
doMethodInfo.Invoke(doer, new[] { stuff });

Thanks in advance and please let me know if this is something that is possible in C#.

Starting with C# 6, you'll be able to avoid the magic string using the new nameof statement:

IDoStuff<object> dummy = null; // don't need a valid instance.
string methodName = nameof(dummy.Do) // yay! no magic strings.

EDIT: @31eee384 pointed out in the comments that the above can be further simplified like this:

string methodName = nameof(IDoStuff<object>.Do);

About the new nameof statement, the documentation has this to say, which seems very much in line with what OP is trying to accomplish:

you often want to capture the string name of a method. Using nameof helps keep your code valid when renaming definitions. Before you had to use string literals to refer to definitions, which is brittle when renaming code elements because tools do not know to check these string literals.


Before C# 6, it's also possible to avoid magic strings by using expressions, but it's a little clunkier. Here is an example that would work in your case.

First, you write the following extension method:

public static string GetMethodName<T>(this T instance, Expression<Action<T>> methodExpression)
{
    if (methodExpression.Body is MethodCallExpression)
    {
        return ((MethodCallExpression)methodExpression.Body).Method.Name;
    }
    else
    {
        throw new ArgumentException(string.Format("Invalid method expression: {0}", methodExpression.Body));
    }
}

And then you can use it like this:

IDoStuff<object> dummy = null; // don't need a valid instance.
string methodName = dummy.GetMethodName(t => t.Do(null)); // yay! still no magic strings.

Create generic method DoIt :

private void DoIt<T>(T stuff, IDoStuff<T> doer) {
    doer.Do(stuff);
}

and call it:

 DoIt(GotThisFromSomewhereElse(), GotThisFromSomewhereElseAlso());

Of course, GotThisFromSomewhereElseAlso and GotThisFromSomewhereElse should be generics as well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM