Skip to content

Instantly share code, notes, and snippets.

@Const-me
Created May 29, 2023 17:18
Show Gist options
  • Save Const-me/5b77905635db85501352eeaa70efaf1b to your computer and use it in GitHub Desktop.
Save Const-me/5b77905635db85501352eeaa70efaf1b to your computer and use it in GitHub Desktop.
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
static class ReflectTest
{
/// <summary>Generic method to call</summary>
public static T GetValue<T>( T value )
{
return value;
}
/// <summary>Synchronization object to protect the cache</summary>
static readonly object syncRoot = new object();
/// <summary>Cache compiled delegates</summary>
static readonly Dictionary<Type, Func<object, object>> cache = new Dictionary<Type, Func<object, object>>();
/// <summary>Lookup delegate from the hash map, compile a new one if not there</summary>
static Func<object, object> getValueDelegate( Type t )
{
lock( syncRoot )
{
if( cache.TryGetValue( t, out Func<object, object>? pfn ) )
return pfn;
pfn = compileDelegate( t );
cache.Add( t, pfn );
return pfn;
}
}
/// <summary>Compile generic method call into the delegate</summary>
[MethodImpl( MethodImplOptions.NoInlining )]
static Func<object, object> compileDelegate( Type t )
{
Type ownerType = typeof( ReflectTest );
const BindingFlags bindingFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
MethodInfo method = ownerType.GetMethod( "GetValue", bindingFlags ) ??
throw new ApplicationException( "GetValue method missing" );
method = method.MakeGenericMethod( t );
ParameterExpression pe = Expression.Parameter( typeof( object ), "obj" );
Expression call = Expression.Call( method, Expression.Convert( pe, t ) );
call = Expression.Convert( call, typeof( object ) );
var lambda = Expression.Lambda<Func<object, object>>( call, pe );
return lambda.Compile();
}
/// <summary>Invoke the generic method with the correct argument type</summary>
static object invoke( object arg ) =>
getValueDelegate( arg.GetType() )( arg );
static void Main( string[] args )
{
int i = 11;
object result = invoke( i );
Console.WriteLine( "{0}", result );
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment