2013-12-03 8 views
23

, например.Как я могу определить, является ли метод C# асинхронным/ожидающим через отражение?

class Foo { public async Task Bar() { await Task.Delay(500); } } 

Если мы отражающие над этим классом и методом, как я могу определить, является ли это фактическим асинхронным/ожидает метод, а не просто метода, который происходит вернуть задачу?

class Foo { public Task Bar() { return Task.Delay(500); } } 
+0

В конце концов, для чего это важно для вас? 'async' является деталью реализации метода и должен быть изменчивым без каких-либо забот потребителей. –

+0

Потому что я пишу перехватчик IoC, который пытается отслеживать начало и конец вызова метода. –

+2

Но если вы считаете, что метод 'async' на самом деле не« завершен »до тех пор, пока задача, которую он вернет, не будет обработана * любым * методом, который возвращает« Задача »как незавершенную до завершения задачи?Также рассмотрите, что метод non-async, возвращающий 'Task', может сделать несколько простых вещей сам, а затем отложить основную часть своей работы до внутреннего метода' async' и просто передать обратно вызывающему пользователю 'Task', созданный этим методом - Планируете ли вы попытаться обнаружить такую ​​ситуацию? –

ответ

33

В моей копии кода, то MethodInfo для метода async содержит следующие элементы в CustomAttributes собственности:

  • DebuggerStepThroughAttribute
  • AsyncStateMachineAttribute

в то время как MethodInfo для нормального метода содержит no объектов в своем CustomAttributes объектов недвижимости.

Похоже, что AsyncStateMachineAttributeshould reliably be found on an async method and not on a standard one.

Редактировать: На самом деле эта страница даже имеет следующие примеры!

Как показано в следующем примере, вы можете определить, помечен ли метод с помощью модификатора Async (Visual Basic) или асинхронного (C# Reference). В этом примере IsAsyncMethod выполняет следующие шаги:

• Получает объект MethodInfo для имени метода с помощью Type.GetMethod.

• Получает объект Type для атрибута с помощью GetType Operator (Visual Basic) или typeof (C# Reference).

• Получает объект атрибута для метода и типа атрибута с помощью метода MethodInfo.GetCustomAttribute. Если GetCustomAttribute возвращает Nothing (Visual Basic) или null (C#), метод не содержит атрибута.

private static bool IsAsyncMethod(Type classType, string methodName) 
{ 
    // Obtain the method with the specified name. 
    MethodInfo method = classType.GetMethod(methodName); 

    Type attType = typeof(AsyncStateMachineAttribute); 

    // Obtain the custom attribute for the method. 
    // The value returned contains the StateMachineType property. 
    // Null is returned if the attribute isn't present for the method. 
    var attrib = (AsyncStateMachineAttribute)method.GetCustomAttribute(attType); 

    return (attrib != null); 
} 
+0

Красота, спасибо. Я думал, что я проверил пользовательские атрибуты, но я проверил те из задачи, которая была возвращена, а не MethodInfo - doh! –

+0

uhm .. если метод.GetCustomAttribute (attType) возвращает null, то при выдаче исключения будет сделано исключение. таким образом, атрибут! = null является избыточным. Использовать как'? Или еще лучше, используйте GetCustomAttribute () – HelloWorld

+0

@ EmilMüller Кастинг 'null' не будет бросать, хотя вы правы, что это необязательно. Это просто аккуратно придать его типу, о котором вы только что просили. Во время этого ответа общая версия не существовала. – Rawling

4

Вот пример двух методов, и я спрашиваю, почему вы думаете, что они должны рассматриваться по-разному:

public static async Task<int> M1(int value) 
    { 
     await Task.Delay(20000); 
     return value; 
    } 

    public static Task<int> M2(int value) 
    { 
     return Task.Delay(20000).ContinueWith<int>(_=>value); 
    } 

Они оба имеют, в пределах handwave, точное такое же поведение во время выполнения - в течение 20 секунд они ничего не делают (и не удерживаются в потоке в течение этого периода), а затем они запускают небольшой делегат, который просто возвращает значение, которое было первоначально передано методу.

И все же вы собираетесь относиться к одному значительно по-другому, чем к другому, потому что я решил использовать компилятор, чтобы скрыть некоторые из сантехники?

+0

Имеет ли [это] (http://stackoverflow.com/a/17000119/215380) количество разного поведения? (Хотя, видимо, если это так, вы все равно можете [обойти это] (http://stackoverflow.com/a/8767406/215380) и получить «идентичное» поведение для 'async'.) – Rawling

+0

@Rawling - да, я сделал подумайте над добавлением чего-то, чтобы настроить ожидание, но именно поэтому я оставил его как «внутри ручной волны» на данный момент - и, конечно, через отражение (инструмент, используемый OP), нет никакого способа узнать, что такое метод async в плане планировщиков, если вы не хотите декомпилировать фактический код метода. –

+0

Ах, ладно, я пропустил ручную волну :) – Rawling