У меня есть настраиваемая среда MVC, в которой я переделываю API маршрутизации. Я пытаюсь придумать чистый способ разделить «настройку» и «выполнение» в моей структуре, который широко использует делегаты и обобщения. Прямо сейчас я представляю себе это со стороны звонящего:

//setup
MyRouter.AddRoute("/foo", () => new MyHandler(), (h) => h.MyMethod);
//h.MyMethod only exists in MyHandler, not in HttpHandler
//execution
MyRouter.Execute(HttpContext);

Сейчас я могу заставить подпись метода AddRoute "работать":

delegate T HandlerInvoker<T>();
delegate string HandlerCallMethod<T>(T handler);
...
public void AddRoute<T>(string pattern, HandlerInvoker<T> invoker, HandlerCallMethod<T> caller) where T is HttpHandler{...}

Если бы мне не нужно было хранить вызывающего и вызывающего, и я мог бы делать это правильно, это сработало бы нормально. Но мне нужно сохранить вызывающий и вызывающий для последующего выполнения.

Текущие вещи, о которых я думал:

  • Сохранение их в List<object> и последующее использование отражения для их вызова. Это кажется чрезвычайно сложным и, вероятно, не слишком эффективным.
  • Перевод AddRoute в исполнение. Это может усложнить использование моего API, но может оказаться моим единственным "хорошим" выбором.
  • Задайте ТАК вопрос :)

Есть ли какой-нибудь хороший способ сохранить эти общие типы без множества мучительных размышлений?

2
Earlz 12 Фев 2013 в 07:19

1 ответ

Лучший ответ

Вы можете сохранить анонимного делегата, который выполняет все преобразования за вас.

Похоже, сработает следующее (никак не проверено):

List<Action> handlers;
handlers.Add(() => caller(invoker()));

Учтите, что это не сработает, если бы вы кешировали invoker.

В этом случае вам нужно сохранить значение, Lazy должно помочь.

List<Action> handlers;
Lazy<T> lazy = new Lazy<T>(invoker);
handlers.Add(() => caller(lazy.Value);

Последний будет создавать только один экземпляр возвращаемого значения invoker за каждый вызов метода. А поскольку lazy является локальной переменной, она автоматически помещается в класс, который сохраняется до тех пор, пока handlers удерживает ссылку для вас.

Обратите внимание, что я проигнорировал шаблон, но, похоже, вам здесь не нужна помощь.

1
Guvante 12 Фев 2013 в 08:13
1
В итоге я сделал что-то похожее на ваш первый метод. Создание делегата, который сделал var h=invoker(); ... h.Foo="bar" etc.. caller(h)
 – 
Earlz
12 Фев 2013 в 11:44