using System.IO;
using System.Reflection.PortableExecutable;
using System.Runtime.CompilerServices;
using System.Runtime.Loader;
namespace Sandbox;
internal static class ReflectionExtensions
{
///
/// The assembly might have a pdb embedded inside. So load it with PEReader and have a look inside to see if it
/// is in there. Then if it is, load the assembly with the pdb.
/// I don't know why this isn't done by default.. but apparently it's not. So we have to do it manually.
///
public static Assembly LoadFromStreamWithEmbeds( this AssemblyLoadContext loadContext, Stream stream )
{
byte[] pdbData = null;
//
// Open PEReader
//
using ( var peReader = new PEReader( stream, PEStreamOptions.LeaveOpen ) )
{
var pdbEntry = peReader.ReadDebugDirectory().FirstOrDefault( x => x.Type == DebugDirectoryEntryType.EmbeddedPortablePdb );
//
// At some point we should probably throw a fit if it doesn't have the pdb.. but we have a few months of addons
// that do not have the pdb embedded, and it doesn't really matter that much.
//
if ( pdbEntry.Type == DebugDirectoryEntryType.EmbeddedPortablePdb )
{
unsafe
{
var pdbReader = peReader.ReadEmbeddedPortablePdbDebugDirectoryData( pdbEntry ).GetMetadataReader();
pdbData = new ReadOnlySpan( pdbReader.MetadataPointer, pdbReader.MetadataLength ).ToArray();
}
}
}
stream.Position = 0;
//
// We have a pdb - load using that!
//
if ( pdbData != null )
{
using var pdbStream = new System.IO.MemoryStream( pdbData );
return loadContext.LoadFromStream( stream, pdbStream );
}
return loadContext.LoadFromStream( stream );
}
///
/// Try to get the event for which this member is a backing field.
///
public static EventInfo GetEventInfo( this FieldInfo fieldInfo )
{
if ( fieldInfo.GetCustomAttribute() is null )
{
return null;
}
var bFlags = BindingFlags.Public | BindingFlags.NonPublic
| (fieldInfo.IsStatic ? BindingFlags.Static : BindingFlags.Instance);
if ( fieldInfo.DeclaringType?.GetEvent( fieldInfo.Name, bFlags ) is not { } eventInfo )
{
return null;
}
if ( eventInfo.EventHandlerType != fieldInfo.FieldType )
{
return null;
}
return eventInfo;
}
#nullable enable
///
/// Looks through the inheritance hierarchy of , including its
/// implemented interfaces, for constructed instances of .
///
public static Type? GetInheritedConstructedGenericType( this Type? type, Type genericTypeDef )
{
if ( type is null )
{
return null;
}
Assert.True( genericTypeDef.IsGenericTypeDefinition );
if ( genericTypeDef.IsInterface )
{
foreach ( var iface in type.GetInterfaces() )
{
if ( iface.IsConstructedGenericType && iface.GetGenericTypeDefinition() == genericTypeDef )
{
return iface;
}
}
return null;
}
while ( type is not null )
{
if ( type.IsConstructedGenericType && type.GetGenericTypeDefinition() == genericTypeDef )
{
return type;
}
type = type.BaseType;
}
return null;
}
#nullable disable
}