2009-09-30 2 views
1

У меня есть защищенный метод в базовом классе, который принимает Func <T>, а затем оборачивается и выполняет с некоторой добавленной добротой. Пример использования:Вызов метода перенаправления внутри делегата

public MyResponse DoSomething(MyRequest request) 
{ 
    return base.Execute(() => this.Channel.DoSomething(request)); 
} 

Что я ищу сделать, это экземпляр делегата и функ переадресацию вызова метода в выражении в другом случае, кроме this.Channel, так что-то вроде:

protected TResponse Execute<TResponse>(Func<TResponse> command) 
{ 
    return command.Method.Invoke(this.otherInstanceOfChannel, command.Target); 
} 

Здесь «this.otherInstanceOfChannel» будет экземпляром другого конкретного класса, чем «this.channel», переданный в исходном вызове, но реализующий тот же интерфейс. Мне просто нужно выяснить, какой метод вызывается и выполнить, что на другом экземпляре, передаваемом в исходных аргументах от вызывающего. Я начал путь MethodCallExpressions и тому подобное, но мое выражение-foo слабое ...

Отредактировано/переписано для наглядности - надеюсь, что эта версия имеет больше смысла.

Спасибо, Matt

+0

Невозможно принять экземпляр в качестве параметра? Это потребует гораздо меньше обмана ... – bobbymcr

+0

Конечно, но пытаясь понять, можно ли делать то, что мне нужно, не нарушая много кода, который вызывает это ... много кода, который я не контролирую, к сожалению ... – matt

+0

Вы имеете в виду, что 'Execute' - это метод, который вы реализуете? То есть вы можете изменить свою подпись и реализацию? –

ответ

1

Да, вы можете это сделать. Нет времени прямо сейчас, чтобы дать вам полное решение, но здесь не скелет, что вы могли бы сделать:

protected TResponse Execute<TResponse>(Expression<Func<TResponse>> command) 
{ 
    // Check that the expression is in the correct format (ie you are calling a method off of a type Channel 
    // Get the name of the method call. Something like: 
     var node = expr.Body as MemberExpression; 
     if (object.ReferenceEquals(null, node)) 
      throw new InvalidOperationException("Expression must be of member access"); 
     var methodName = node.Member.Name; 
    // Use reflection to invoke methodName on otherInstanceOfChannel 
    // Cast the results to TResponse and return 
} 

Как вы можете видеть, единственный реальный трюк является использование выражения <>. Изменение типа прозрачно для любого клиентского кода - им вообще не нужно менять. Here is some code, чтобы вы начали с разбора деревьев выражений.

+0

Я обнаружил еще один способ сделать это без выражения обезьяны, но ваш метод действительно работал так, как я пытался это сделать - спасибо - запомнит это на будущее. – matt

1

Я считаю, что вы можете предоставить экземпляр в лямбда-выражения, как так:

IMyChannel myChannelInstance = MyChannelInstanceFactory.Create(); 
Execute(() => myChannelInstance.DoSomething(request)) 

Если это не может быть сделано с лямбда-выражения, и я уверен, что они могут вас может изменить это на делегата, и он будет работать нормально. Выражение лямбда указывает на блок выполнения кода, и таким образом вы можете поместить все, что соответствует аргументам выражения в этом блоке кода.

+0

Извините, возможно, не было ясно с моим вопросом - см. Мой ответ на Павла выше ... – matt

+0

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

+0

Определенно - если я не могу выполнить эту работу только в рамках реализации метода Execute, то я буду смотреть на способы измените подпись метода, удовлетворяющую моим потребностям, и заставите всех менять свой код - пытался избежать этого, если бы мог. – matt

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