2010-12-30 5 views
0

Я пытаюсь создать маршрутизатор для веб-приложения (да, я знаю, что решения уже существуют).Как обратиться к методу?

До сих пор я получил это:

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

И это:

Route[] routes = { 
     new Route(@"/user:(?<id>\d+)", typeof(UserController)) 
    }; 

Когда URL совпадает регулярное выражение, он должен вызвать метод action в классе controller. Я думаю, typeof() - единственный способ, которым я могу пройти класс, но как насчет метода?

Я думаю, что MethodInfo - это объект, который я хочу, потому что с этим я должен его вызывать, но с точки зрения API, какой должен быть 3-й аргумент для конструктора Route и как его называть?

Я предпочитаю строго типизированное решение, а не некоторые строфарные махинации.

+0

Каким должен быть метод действия? –

+0

@Martinho: А? «действие» в порядке. Мой вопрос о синтаксисе. В идеале я бы просто написал «новый маршрут» («pattern», UserController.Method), но C# не поддерживает такой синтаксис. – mpen

ответ

1

Вы ищете несуществующий infoof operator.

К сожалению, его не существует.

Самый простой ответ - взять строку.
В качестве альтернативы вы можете взять expression tree.
Недостаток использования дерева выражений состоит в том, что ваш вызывающий объект должен передать все параметры.
Вы можете использовать это в своей структуре (взяв Expression<Func<parameters, ResultType>>) и, возможно, даже скомпилировать дерево выражений, чтобы вызвать действия. (Что приведет к гораздо быстрее, чем звонки отражения)

+1

В этой статье «infoof» упоминаются несколько проблем, о которых я действительно не думал ... возможно, лучше и проще работать со строками, даже если я не получу безопасность типа компиляции. – mpen

+0

Да; это отличный пост в блоге. – SLaks

+0

Чтобы справиться с двусмысленностями, я бы хотел, чтобы он возвращал 'MethodInfo []' со всеми возможными совпадениями :) – mpen

1

Вы можете создать что-то вроде этого:

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

и использовать его как это:

MethodInfo action = GetMethodInfo((UserController c) => c.ActionMethod()); 
// or 
MethodInfo action = GetMethodInfo((UserController c) => 
             c.ActionMethodWithParams(default(int))); 

Это не будет вызывать метод сразу потому что это дерево выражений, т. е. синтаксическое дерево, представляющее вызов метода.

+0

Это предполагает, что методы контроллера не принимают никаких параметров. В противном случае необходимо передать «null» и «default()» – statenjason

+0

Ah! Несколько человек упомянули эти «деревья выражений», но никто не представил пример кода. Думаю, я вижу, как это работает сейчас.Спасибо :) – mpen

+0

@statenjason: Нет, он ничего не предполагает о действиях контроллера (за пару минут он принял возвращаемое значение, но никогда ничего о параметрах). Но да, вы должны пройти фиктивные значения. Я предпочитаю по умолчанию, потому что он помогает выбирать между перегрузками. –

3

Я не думаю, что есть способ ссылаться на метод экземпляра в c sharp без экземпляра. Если вы не хотите, чтобы пользователь API определял объект MethodInfo для передачи, имя строки может быть наилучшим способом.

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); 
    } 
} 
+0

Неплохое решение, спасибо: D – mpen

+0

Подождите ... 'new Callback (Action)', если 'Action' - это метод экземпляра в UserController ... как это вообще можно скомпилировать? – mpen

+0

@Ralph: [Делегаты] (http://msdn.microsoft.com/en-us/library/ms173171 (VS.80% 29.aspx), такие как «Обратный звонок», представляют методы, как в «фрагментах кода, которые могут быть run ». MethodInfo представляет метод, как в« члене с именем и подписью ». –

Смежные вопросы