2009-12-03 2 views
1

У меня есть функция, которая завершает вызов одному из моих типов сокетов. Если есть ошибка, я хочу иметь возможность печатать предупреждение и повторять попытку. В предупреждении я хочу иметь имя метода. Однако он был объявлен как лямбда. Возможно ли это?C# (.NET 3.5) Есть ли способ получить это имя функции?

Как вызвать функцию (предположим, что функция называется myMain):

SafeSocketCommand(() => this.mySocket.ReadCurrentBuffer()); 

Основная функция упаковка:

protected TResult SafeSocketCommand<TResult>(Func<TResult> socketCommand) 
{ 
    TResult retValue = default(TResult); 
    try 
    { 
     retValue = socketCommand(); 
    } 
    catch (PacketLost) 
    { 
     ReportToLogs("Timeout on command '" + socketCommand.Method.Name); 
    } 
    return retValue; 
} 

Но socketCommand.Method.Name дает мне метод вызова (из стека Trace?) '< myMain> b__3', и я хочу, чтобы действительная функция вызывалась socketCommand (mySocket.ReadCurrentBuffer). Возможно ли получить эту информацию в любом месте или она потеряна из-за объявления в лямбда?

EDIT:

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

int i = SafeSocketCommand(() => this.mySocket.FunctionReturnsInt()) 
bool b = SafeSocketCommand(() => this.mySocket.FunctionReturnsBool(string s)) 
object o = SafeSocketCommand(() => this.mySocket.Complicated(string s, int i, bool b)) 

Он также не обрабатывает и не использует подпись возврата типа при перегрузке:

protected void SafeSocketCommand(Action socketCommand) 
{ 
    SafeSocketCommand(() => { socketCommand(); return 0; }); 
} 
+0

Если делегат, который прошел мимо, имеет 20 строк кода в нем, вы просто хотите, чтобы строка «возвращалась»? – CSharpAtl

+0

В моей реализации не было бы 20 строк, но, ради аргументов, скажем, я просто хочу эту строку. – cgyDeveloper

ответ

5

Если изменить ваш SafeSocketCommand, чтобы принять Expression<Func<TResult>>, то вы получите доступ к дереву выражения, которое представляет тело лямбды, из которого можно напрямую обращаться к ReadCurrentBuffer позвонить напрямую.

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

+0

Интересно, я не знал о выражении. Поскольку это уже не обычный анонимный метод, приведет ли он к сбою любого из моих различных соглашений о вызове (где я могу звонить независимо от сигнатуры функции)? – cgyDeveloper

+0

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

+0

Тогда я должен сделать снимок. Поскольку формат лямбда всегда является одним из двух стилей (в зависимости от того, добавлен ли он: 0, добавлен или нет), должно быть достаточно просто разобрать дерево для имени моей функции. – cgyDeveloper

2

Нет, потому что лямбда не имеют имен; они анонимные функции. Вы можете получить имя метода из последнего StackFrame, хотя:

new StackFrame(1).GetMethod().Name; 
+0

Может ли исключение быть в StackFrame в этот момент? Что, если его поймают, переупаковывают и бросают второй раз? – cgyDeveloper

+0

Вы думаете о стеке ** trace **. Этот код просто проверяет отдельный кадр. –

+0

Хороший способ получить имя метода без < > b__3, но мне, вероятно, придется попробовать использовать выражение и разбор дерева, если я хочу имя функции. – cgyDeveloper

2

Func<TResult> только один делегат. Вместо использования лямбда создайте метод, который соответствует сигнатуре Func<TResult> и вызовет это. Таким образом, у вас будет любое имя, которое вы хотите.

SafeSocketCommand(MyNewMethod); 

...

public TResult MyNewMethod() 
{ 
    return this.mySocket.ReadCurrentBuffer(); 
} 
0

В этом случае вы можете просто использовать этот вызов. Это будет быстрее и меньше сгенерированный код.

SafeSocketCommand(mySocket.ReadCurrentBuffer); 

В общем, StackTrace объекте Exception содержит полную информацию, которую вы ищете, много более точно, чем печать имени метода, или вы можете использовать TargetSite свойства для имени методы, исключение.

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