TaskResultBinder
using System;
using System.Collections.ObjectModel;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
namespace DotNext.Runtime.CompilerServices
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
internal sealed class TaskResultBinder : CallSiteBinder
{
private const string PropertyName = "Result";
private const BindingFlags PropertyFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy;
private static Expression BindMissingProperty(Expression target, out Expression restrictions)
{
restrictions = Expression.TypeEqual(target, typeof(Task));
target = Expression.Call(target, "GetAwaiter", Type.EmptyTypes, Array.Empty<Expression>());
target = Expression.Call(target, "GetResult", Type.EmptyTypes, Array.Empty<Expression>());
return Expression.Block(typeof(object), target, Expression.Field(null, typeof(Missing), "Value"));
}
private static Expression BindProperty(PropertyInfo resultProperty, Expression target, out Expression restrictions)
{
restrictions = Expression.TypeIs(target, resultProperty.DeclaringType);
target = Expression.Call(typeof(Unsafe), "As", new Type[1] {
resultProperty.DeclaringType
}, target);
target = Expression.Property(target, resultProperty);
if (!target.Type.IsValueType)
return target;
return Expression.Convert(target, typeof(object));
}
private static Expression Bind(object targetValue, Expression target, LabelTarget returnLabel)
{
PropertyInfo property = targetValue.GetType().GetProperty("Result", BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
target = (((object)property == null) ? BindMissingProperty(target, out Expression restrictions) : BindProperty(property, target, out restrictions));
target = Expression.Return(returnLabel, target);
target = Expression.Condition(restrictions, target, Expression.Goto(CallSiteBinder.UpdateLabel));
return target;
}
public override Expression Bind(object[] args, ReadOnlyCollection<ParameterExpression> parameters, LabelTarget returnLabel)
{
return Bind(args[0], parameters[0], returnLabel);
}
}
}