C # (.NET 3.5) Есть ли способ получить имя этой функции? - PullRequest
1 голос
/ 03 декабря 2009

У меня есть функция, которая переносит вызов к одному из моих типов сокетов. Если есть ошибка, я хочу вывести предупреждение и повторить попытку. В предупреждении я хочу указать имя метода. Тем не менее, он был объявлен как лямбда. Это вообще возможно?

Как я вызываю функцию (предположим, что функция называется 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 дает мне вызывающий метод (из трассировки стека?) ' 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; });
}

Ответы [ 4 ]

5 голосов
/ 03 декабря 2009

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

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

2 голосов
/ 03 декабря 2009

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

SafeSocketCommand(MyNewMethod);

...

public TResult MyNewMethod()
{
    return this.mySocket.ReadCurrentBuffer();
}
2 голосов
/ 03 декабря 2009

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

new StackFrame(1).GetMethod().Name;
0 голосов
/ 03 декабря 2009

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

SafeSocketCommand(mySocket.ReadCurrentBuffer);

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...