How to refer to a method?
I'm trying to create a router for a web application (yes, I know solutions already exist).
Thus far I've got this:
class Route
{
public static RegexOptions DefaultOptions = RegexOptions.IgnoreCase;
Regex regex;
Type controller;
MethodInfo action;
public Route(string pattern, Type controller)
{
this.regex = new Regex(string.Format("^(?:{0})$", pattern), DefaultOptions);
this.controller = controller;
}
}
And this:
Route[] routes = {
new Route(@"/user:(?<id>\d+)", typeof(UserController))
};
When the URL matches that regex, it should call the method action
in class controller
. I'm thinking typeof()
is the only way I can pass the class around, but how about the method?
I think MethodInfo
is the object I want, because with that I should be able to invoke it, but from an API perspective, what should the 3rd argument to Route
constructor be, and how should we call it?
I prefer a strongly-typed solution rather than some str开发者_运维知识库ing shenanigans.
I don't think there is a way to refer to a instance method in c sharp without an instance. Unless you want the user of the API to define a MethodInfo object to pass in, string name may be the best way.
static class Program
{
static void Main()
{
Route r = new Route("pattern", typeof(UserController), "Action");
}
}
public class Route
{
public Route(string pattern, Type type, string methodName)
{
object objectToUse = Activator.CreateInstance(type, null);
MethodInfo method = type.GetMethod(methodName);
string[] args = new string[1];
args[0] = "hello world";
method.Invoke(objectToUse, args);
}
}
public class UserController
{
public void Action(string message)
{
MessageBox.Show(message);
}
}
You're looking for the non-existent infoof
operator.
Unfortunately, it doesn't exist.
The simplest answer is to take a string.
Alternatively, you can take an expression tree.
The disadvantage to taking an expression tree is that your caller must pass all parameters.
You could work that into your framework (by taking an Expression<Func<parameters, ResultType>>
), and perhaps even compile the expression tree to call the actions. (which will result in much faster calls than reflection)
You can create something like this:
MethodInfo GetMethodInfo(LambdaExpression expression)
{
var call = expression.Body as MethodCallExpression;
if(call == null) throw new ArgumentException("Must be a method call","expression");
return call.Method;
}
MethodInfo GetMethodInfo<T>(Expression<Action<T>> expression)
{
return GetMethodInfo(expression);
}
MethodInfo GetMethodInfo<T, TResult>(Expression<Func<T, TResult>> expression)
{
return GetMethodInfo(expression);
}
And use it like this:
MethodInfo action = GetMethodInfo((UserController c) => c.ActionMethod());
// or
MethodInfo action = GetMethodInfo((UserController c) =>
c.ActionMethodWithParams(default(int)));
This won't call the method immediately because it is an expression tree, i.e., a syntactic tree representing the method call.
精彩评论