public static bool IsAsyncEnumerable(this Type type, out AsyncEnumerableInfo enumerableInfo) { if (type is null) { throw new ArgumentNullException(nameof(type)); } if (!type.IsAsyncEnumerableType(out var getAsyncEnumerator)) { enumerableInfo = default; return(false); } var isEnumerator = getAsyncEnumerator.ReturnType.IsAsyncEnumeratorType(out var current, out var moveNextAsync, out var disposeAsync); enumerableInfo = new AsyncEnumerableInfo(getAsyncEnumerator, new AsyncEnumeratorInfo(current, moveNextAsync, disposeAsync)); return(isEnumerator); }
public AsyncEnumerableWrapper(TEnumerable instance, AsyncEnumerableInfo info) { Instance = instance; Info = info; }
/// <summary> /// Gets a value indicating whether 'await foreach' considers <see cref="System.Type"/> to be enumerable. /// </summary> /// <param name="type">The <see cref="System.Type"/> to test.</param> /// <param name="enumerableInfo">If methods returns <c>true</c>, contains information on the methods 'await foreach' will use to enumerate.</param> /// <param name="errors">Gets information on what error caused the method to return <c>false</c>.</param> /// <returns><c>true</c> if 'await foreach' considers <see cref="System.Type"/> to be enumerable; otherwise, <c>false</c>.</returns> public static bool IsAsyncEnumerable(this Type type, [NotNullWhen(true)] out AsyncEnumerableInfo?enumerableInfo, out Errors errors) { if (!type.IsInterface) { var getAsyncEnumerator = type.GetPublicInstanceMethod(nameof(IAsyncEnumerable <int> .GetAsyncEnumerator), typeof(CancellationToken)); if (getAsyncEnumerator is null) { getAsyncEnumerator = type.GetPublicInstanceMethod(nameof(IAsyncEnumerable <int> .GetAsyncEnumerator)); } if (getAsyncEnumerator is not null) { var enumeratorType = getAsyncEnumerator.ReturnType; var current = enumeratorType.GetPublicInstanceReadProperty(nameof(IEnumerator.Current)); if (current is null) { enumerableInfo = default; errors = Errors.MissingCurrent; return(false); } var moveNextAsync = enumeratorType.GetPublicInstanceMethod(nameof(IAsyncEnumerator <int> .MoveNextAsync), Type.EmptyTypes); if (moveNextAsync is null) { enumerableInfo = default; errors = Errors.MissingMoveNext; return(false); } _ = enumeratorType.IsAsyncDisposable(out var dispose); enumerableInfo = new AsyncEnumerableInfo( getAsyncEnumerator: getAsyncEnumerator, new AsyncEnumeratorInfo(current, moveNextAsync) { DisposeAsync = dispose, IsValueType = getAsyncEnumerator.ReturnType.IsValueType, IsAsyncEnumeratorInterface = enumeratorType.IsInterface, } ); errors = Errors.None; return(true); } } if (type.ImplementsInterface(typeof(IAsyncEnumerable <>), out var genericArguments)) { var enumerableType = typeof(IAsyncEnumerable <>).MakeGenericType(genericArguments[0]); var enumeratorType = typeof(IAsyncEnumerator <>).MakeGenericType(genericArguments[0]); enumerableInfo = new AsyncEnumerableInfo( getAsyncEnumerator: enumerableType.GetPublicInstanceDeclaredOnlyMethod(nameof(IAsyncEnumerable <int> .GetAsyncEnumerator), typeof(CancellationToken)) !, new AsyncEnumeratorInfo( current: enumeratorType.GetPublicInstanceDeclaredOnlyReadProperty(nameof(IAsyncEnumerator <int> .Current)) !, moveNextAsync: enumeratorType.GetPublicInstanceDeclaredOnlyMethod(nameof(IAsyncEnumerator <int> .MoveNextAsync), Type.EmptyTypes) !) { DisposeAsync = typeof(IAsyncDisposable).GetPublicInstanceDeclaredOnlyMethod(nameof(IAsyncDisposable.DisposeAsync), Type.EmptyTypes), IsAsyncEnumeratorInterface = true, }