Search code examples
c#taskpostsharp

Access result of Task<T> without knowing T - postsharp


I am trying to use postsharp modify the return values of async methods. Is it possible to get the result of a Task at runtime without knowing T?

i.e.

public void OnSuccess(MethodExecutionArgs args)
{

var returnValue = args.ReturnValue;

// returnType is Task<T>
var returnType = returnValue.GetType();    

// Is it possible to access the result of the task?

// If T was known then I could cast:
// ((Task<T>) returnValue).ContinueWith(t => t.Result ...)
}

Solution

  • Without reflection, you'd need to use and interface. Also with PostSharp 5.0, you get the result itself there in the OnSuccess method instead of the Task<>.

    This example works with PostSharp 5.0:

    using System;
    using System.Threading.Tasks;
    using PostSharp.Aspects;
    using PostSharp.Serialization;
    
    namespace OnMethodBoundaryAsyncTest
    {
        interface IDirtiness
        {
            bool Dirty { get; set; }
        }
    
        class MyClassWithSomeDirtyObjects : IDirtiness
        {
            public bool Dirty { get; set; }
        }
    
        [PSerializable]
        class ReportDirtinessAttribute : OnMethodBoundaryAspect
        {
            public override void OnSuccess( MethodExecutionArgs args )
            {
                IDirtiness maybeDirtyObject = args.ReturnValue as IDirtiness;
    
                if ( maybeDirtyObject != null )
                {
                    string dirty = maybeDirtyObject.Dirty ? "is" : "is not";
                    Console.WriteLine($"{maybeDirtyObject} {dirty} dirty.");
                }
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                CreateObject( false ).GetAwaiter().GetResult();
                CreateObject( true ).GetAwaiter().GetResult();
            }
    
            [ReportDirtiness(ApplyToStateMachine = true)]
            static async Task<MyClassWithSomeDirtyObjects> CreateObject( bool dirty )
            {
                return new MyClassWithSomeDirtyObjects {Dirty = dirty};
            }
        }
    }