2017-02-17 5 views
3

작업 내부 상태 시스템의 상태를 조작하는 생각을 가지고 놀고 있지만 실제로 내 상태 시스템 참조에 액세스하는 방법을 찾는 데 문제가 있습니다. 작업 방법.작업 상태 기계에 대한 실제 참조 얻기

class Test 
{ 
    async Task IndexAsync() 
    { 
     var nottheactualtype = GetType(); //This references the "Test" class, but this operation is actually located in the nested state machine class named "IndexAsync", in the method "MoveNext()". 
     var actualcalledmethod = new StackTrace().GetFrame(0).GetMethod(); //This shows the actual method currently being run: IndexAsync.MoveNext(). 
     //But how do I get the reference to my current IndexAsync class? 
    } 
} 

현재 실행중인 생성 된 상태 시스템의 참조에 액세스하려면 어떻게합니까?

+0

이는 방법 자체 내에서해야합니까? 나는 당신을 도울 수있는 https://github.com/jskeet/DemoCode/tree/master/Abusing%20CSharp/Code/FunWithAwaiters에서 이런 종류의 일을하는 많은 코드를 가지고있다. 그러나 그것은 상태를 얻지 않는 경향이있다. 비동기 메서드 내에서 * machine *. –

+0

나는 그렇게 믿는다. async 메서드 내의 특정 위치에서 상태 머신의 어느 상태가 실행 중인지보고 싶습니다. 그보다 더 많은 것이 있지만, 본질적으로 현재 실행중인 상태 시스템의 멤버에 액세스하려고합니다. 리플렉션을 통해 액세스 할 수있는 멤버이며 생성 된 클래스의 유형에 액세스 할 수 있습니다. 하지만 실제로 참조 할 수있는 방법을 찾지 못하고 있습니다. – Micael

+0

그래, 내가 뭔가를 생각해 냈는데, 나는 그것을 시험해 볼 필요가있다. –

답변

0

당신은 변형으로 스택에 클래스에서 첫 번째 메서드 호출을 수행 할 수 있습니다

var nottheactualtype = GetType(); 
var actualcalledmethod = new StackTrace().GetFrames().FirstOrDefault(x => x.GetMethod().ReflectedType == nottheactualtype); 
+0

미안하지만,'this.GetType()'과 같은 결과를 보여줍니다. 문제는 컴파일러에서 생성 된 상태 시스템 클래스를 숨기려면 컴파일러가 "this"참조를가립니다. StackTrace를 사용하면 상태 시스템 클래스의 유형 인스턴스에 액세스 할 수 있지만 실제 실행중인 인스턴스에 액세스해야합니다. – Micael

0

한 가지 방법은 IndexAsync 클래스의 참조 또는 인스턴스를 Test 클래스에 전달하는 것입니다.

또 다른 옵션은 리플렉션을 통해 개인용 배경 필드에 할당하는 것입니다.하지만 리플렉션이 느려질 수 있으므로 첫 번째 옵션을 선호합니다.

코드를 더 많이 공유하면 자신의 케이스에서 코드를 쉽게 식별 할 수 있습니다.

+0

아쉽게도 작동하지 않습니다. 중첩 된 IndexAsync 클래스는 컴파일러에서 생성됩니다. [이 블로그 항목은 비동기 작업의 내부 구조가 어떻게 작동하는지 아주 잘 설명합니다. [link] (https://weblogs.asp.net/dixin/understanding-c-sharp-async-await -1 컴파일)), 런타임에만 액세스 할 수 있습니다. – Micael

1

그것은 불쾌한, 그리고 (이 구현 세부 사항에 따라 다름) 작동하지 않을 것 - 그러나 이것은 나를 위해 작동 ... 그것은 기본적으로 대기 상태로 계속할 수있는 상태 기계를 유발합니다. 그런 다음 계속 대표단의 대상에서 상태 시스템을 가져올 수 있습니다.

못생긴, 추한, 못생긴 코드

...하지만이하는 저를 위해 일하고 :

using System; 
using System.Reflection; 
using System.Threading.Tasks; 
using System.Runtime.CompilerServices; 
using static System.Reflection.BindingFlags; 

public class StateMachineProvider 
{ 
    private static readonly StateMachineProvider instance = new StateMachineProvider(); 

    public static StateMachineProvider GetStateMachine() => instance; 

    public StateMachineAwaiter GetAwaiter() => new StateMachineAwaiter(); 

    public class StateMachineAwaiter : INotifyCompletion 
    { 
     private Action continuation; 

     public bool IsCompleted => continuation != null; 

     public void OnCompleted(Action continuation) 
     { 
      this.continuation = continuation; 
      // Fire the continuation in a separate task. 
      // (We shouldn't just call it synchronously.) 
      Task.Run(continuation); 
     } 

     public IAsyncStateMachine GetResult() 
     { 
      var target = continuation.Target; 
      var field = target.GetType() 
           .GetField("m_stateMachine", NonPublic | Instance); 
      return (IAsyncStateMachine) field.GetValue(target); 
     } 
    } 
} 

class Test 
{ 
    static void Main() 
    { 
     AsyncMethod().Wait(); 
    } 

    static async Task AsyncMethod() 
    { 
     int x = 10; 
     IAsyncStateMachine machine = await StateMachineProvider.GetStateMachine(); 
     Console.WriteLine($"x={x}"); // Force the use across an await boundary 
     Console.WriteLine($"State machine type: {machine.GetType()})"); 
     Console.WriteLine("Fields:"); 
     var fields = machine.GetType().GetFields(Public | NonPublic | Instance); 
     foreach (var field in fields) 
     { 
      Console.WriteLine($"{field.Name}: {field.GetValue(machine)}"); 
     } 
    } 
} 

출력 :

x=10 
State machine type: Test+<AsyncMethod>d__1) 
Fields: 
<>1__state: -1 
<>t__builder: System.Runtime.CompilerServices.AsyncTaskMethodBuilder 
<x>5__1: 10 
<machine>5__2: Test+<AsyncMethod>d__1 
<>s__3: 
<>s__4: System.Reflection.FieldInfo[] 
<>s__5: 6 
<field>5__6: System.Reflection.FieldInfo <field>5__6 
<>u__1: 
+0

나는 계속의 힘이 꽤 못생긴다는 ​​것에 동의하지만, 그 접근법은 훌륭하고 분명히 가치가있다. 고맙습니다! – Micael