2016-11-16 6 views
-1

Я пытаюсь определить, был ли вызван конкретный метод методом async.Как точно определить, был ли метод вызван методом асинхронизации

This answer (который был предоставлен, описывая несколько иной набор обстоятельств), предлагаемый с использованием атрибута CallerMemberName, чтобы найти имя вызывающего метода. Действительно, подпись моего метода выглядит следующим образом:

public void LogCallAsync([CallerMemberName] string caller = "", params object[] parameters) 

, который прекрасно работает, если вы делаете что-то вроде

logger.LogCallAsync(); 

Он также будет работать хорошо, если у вас есть фиксированное число параметров. Однако, учитывая, что следующий параметр типа params object[], очевидно, что это не так, так что если вы попытаетесь сделать что-то вроде

logger.LogCallAsync(someObject, someOtherObject) 

Я получаю компиляции исключение, потому что someObject не является строкой. В качестве обходного пути я попытался сделать следующее:

logger.LogCallAsync(nameof(CurrentMethod), someObject, someOtherObject); 

, который довольно уродливый. На самом деле, я бы предпочел, если бы мне не сделал, так что если у кого-то есть предложения в этом отношении, это было бы здорово, но на мой главный вопрос: есть ли способ предотвратить обращение людей к этому неправильно? В частности, я хотел бы знать, является ли «CurrentMethod» , фактически, фактическим методом async.

Если я рассматриваю пример StackTrace, например, существует ли надежный способ говорить на основе этого? This article (если я читаю его правильно), похоже, подразумевает, что мое текущее решение (см. Мой пример кода ниже) является правильным, но это не действительно «авторитетный» источник, и ему сейчас около 5 лет.

Позвольте мне показать пример кода для иллюстрации того, как я пытаюсь решить это прямо сейчас:

private static void GetCaller() 
    { 
     StackTrace stack = new StackTrace(); 
     MethodBase method = stack.GetFrame(1).GetMethod(); 

     Trace.TraceInformation("Method name: " + method.Name); 
    } 

    // Some arbitrary async method 
    private static async Task UseReflection() 
    { 
     // Do some kind of work 
     await Task.Delay(100); 

     // Figure out who called this method in the first place 
     // I want some way of figuring out that the UseReflection method is async 
     GetCaller(); 
    } 

    static void Main(string[] args) 
    { 
     // AsyncPump is basically to make Async work more like it does on a UI application 
     // See this link: https://blogs.msdn.microsoft.com/pfxteam/2012/01/20/await-synchronizationcontext-and-console-apps/ 
     AsyncPump.Run(async() => 
     { 
      // In this case, it identifies the calling method as "MoveNext" 
      // Question: in cases like this, will this always be the case (i.e. will it always be MoveNext)? 
      await UseReflection(); 
     }); 

     // In this case, it identifies the calling method as "Main" 
     GetCaller(); 
    } 

Я использую Visual Studio 2015 и .NET 4.6, для чего это стоит. Поэтому мой вопрос: могу ли я гарантировать, что код всегда будет работать так, как это было у меня выше? Например, если GetCaller был вызван методом асинхронного вызова, будет ли всегда получить MoveNext с трассировкой стека? Кроме того, кто-нибудь знает, если Microsoft документирует это где-нибудь (в случае, если меня попросят доказать, что мое решение будет работать)?

EDIT: Основная цель здесь - записать имя и параметры метода, который называется регистратором. Если вызывающий абонент не асинхронный, то я знаю, что следующий код

StackTrace stack = new StackTrace(); 
MethodBase method = stack.GetFrame(1).GetMethod(); 

даст мне информацию о том, кто вызывающее. Однако это явно не будет работать, если вызывающий абонент async.В этом случае я в настоящее время сделать следующее:

StackTrace st = new StackTrace(); 
StackFrame callFrame = st.GetFrames().ToList().FirstOrDefault(x => x.GetMethod().Name == caller); 

где caller это имя метода вызова, который я прошел, как в подписи я перечислил выше:

public void LogCallAsync([CallerMemberName] string caller = "", params object[] parameters) 

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

+3

Ваш вопрос имеет [XY Problem] (http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem), написанный на нем. Мне трудно поверить, что полезно каким-либо образом узнать, является ли ваш вызывающий объект фактически методом, объявленным как «async», неважно, возможно. Методы могут выглядеть как «async» -классифицированный метод, фактически не являясь одним из них, а другие методы могут вести себя аналогично методам async (т. Е. Таким образом, как вы могли бы позаботиться), не выглядя похожим на один. Какая у вас проблема, которую вы на самом деле хотите решить? –

+0

@PeterDuniho Это может быть случай с XY проблемой, если я ошибаюсь, что было бы хорошо знать. Я отредактирую, чтобы включить более подробную информацию в ближайшее время. – EJoshuaS

+0

@PeterDuniho Я отредактировал - это проясняет это? – EJoshuaS

ответ

2

Да, все методы async в конечном итоге перемещаются в MoveNext.

+0

Итак, если я сделаю что-то вроде того, что я делаю в своем примере, это определенно будет работать, как я думаю, что это так? Знаете ли вы, что Microsoft документирует это где-нибудь (если мой босс попросит меня доказать, что он сработает)? – EJoshuaS

+2

@EJoshuaS, я не думаю, что его «официально» задокументировано с момента его за кулисами, но этот пост в блоге должен вернуть вашего босса с вашей спиной:) ... http://apmblog.dynatrace.com/2014/ 10/09/behind-net-4-5-async-scene-performance-impact-asynchronous-programming-c/... объясняет, как компилятор генерирует асинхронный код. – SledgeHammer

+3

@EJoshuaS Обратите внимание, что вы также можете быть внутри метода с именем «MoveNext», если вы явно назовете метод, который или вы пишете генератор. Например: 'IEnumerable TestIt() {\t return return 1; доходность возврата 2; } '. Недостаточно, чтобы решить, что это метод асинхронного тестирования. * Почему * имеет значение, если вызывающий абонент асинхронный или нет? – Rob