File: System\Reflection\TypeLoading\Assemblies\RoAssembly.GetForwardedTypes.cs
Web Access
Project: src\src\libraries\System.Reflection.MetadataLoadContext\src\System.Reflection.MetadataLoadContext.csproj (System.Reflection.MetadataLoadContext)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections.Generic;
using System.Diagnostics;
 
namespace System.Reflection.TypeLoading
{
    /// <summary>
    /// Base class for all Assembly objects created by a MetadataLoadContext.
    /// </summary>
    internal abstract partial class RoAssembly
    {
        public sealed override Type[] GetForwardedTypes()
        {
            List<Type> types = new List<Type>();
            List<Exception>? exceptions = null;
 
            IterateTypeForwards(
                delegate (RoAssembly redirectedAssembly, ReadOnlySpan<byte> ns, ReadOnlySpan<byte> name)
                {
                    Type? type = null;
                    Exception? exception = null;
                    if (redirectedAssembly is RoExceptionAssembly exceptionAssembly)
                    {
                        exception = exceptionAssembly.Exception;
                    }
                    else
                    {
                        // GetTypeCore() will follow any further type-forwards if needed.
                        type = redirectedAssembly.GetTypeCore(ns, name, ignoreCase: false, out Exception? e);
                        if (type == null)
                        {
                            exception = e;
                        }
                    }
 
                    Debug.Assert((type != null) != (exception != null)); // Exactly one of these must be non-null.
 
                    if (type != null)
                    {
                        types.Add(type);
                        AddPublicNestedTypes(type, types);
                    }
                    else
                    {
                        exceptions ??= new List<Exception>();
                        exceptions.Add(exception!);
                    }
                }
            );
 
            if (exceptions != null)
            {
                int numTypes = types.Count;
                int numExceptions = exceptions.Count;
                types.AddRange(new Type[numExceptions]); // add one null Type for each exception.
                exceptions.InsertRange(0, new Exception[numTypes]); // align the Exceptions with the null Types.
                throw new ReflectionTypeLoadException(types.ToArray(), exceptions.ToArray());
            }
 
            return types.ToArray();
        }
 
        private static void AddPublicNestedTypes(Type type, List<Type> types)
        {
            foreach (Type nestedType in type.GetNestedTypes(BindingFlags.Public))
            {
                types.Add(nestedType);
                AddPublicNestedTypes(nestedType, types);
            }
        }
 
        /// <summary>
        /// Intentionally excludes forwards to nested types.
        /// </summary>
        protected delegate void TypeForwardHandler(RoAssembly redirectedAssembly, ReadOnlySpan<byte> ns, ReadOnlySpan<byte> name);
        protected abstract void IterateTypeForwards(TypeForwardHandler handler);
    }
}