Skip to content

Instantly share code, notes, and snippets.

@Warrenn
Created July 1, 2015 14:43
Show Gist options
  • Save Warrenn/a1abc5a14c250145708d to your computer and use it in GitHub Desktop.
Save Warrenn/a1abc5a14c250145708d to your computer and use it in GitHub Desktop.
A dynamic object that can be used to call Methods when only Type object is available
using System;
using System.Collections.Concurrent;
using System.Dynamic;
using System.Linq;
using System.Reflection;
public class GenericExpando : DynamicObject
{
private readonly object instance;
private readonly Type staticType;
private static readonly ConcurrentDictionary<string, Lazy<MethodInfo>> MethodInfos =
new ConcurrentDictionary<string, Lazy<MethodInfo>>();
public const BindingFlags StaticFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreCase;
public const BindingFlags InstanceFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase;
public GenericExpando(Type staticType)
{
this.staticType = staticType;
}
public GenericExpando(object instance)
{
this.instance = instance;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
result = null;
if (args.Length < 1)
{
return false;
}
if (args[0] == null)
{
return false;
}
Type[] genericTypes = null;
var type = args[0] as Type;
if (type != null)
{
genericTypes = new[] { type };
}
var types = args[0] as Type[];
if (types != null)
{
genericTypes = types;
}
if ((genericTypes == null) || (genericTypes.Length == 0))
{
return false;
}
var callingArgs = new object[args.Length - 1];
for (var i = 1; i < args.Length; i++)
{
callingArgs[i - 1] = args[i];
}
if (staticType != null)
{
result = InvokeStatic(
binder.Name,
staticType,
genericTypes,
callingArgs);
return true;
}
if (instance == null)
{
return false;
}
result = InvokeInstance(
binder.Name,
instance,
genericTypes,
callingArgs);
return true;
}
private static object Invoke(
string methodName,
object instance,
Type callingType,
Type[] genericTypes,
object[] arguments)
{
var argumentTypes = arguments.Select(a => a.GetType()).ToArray();
var flags = (instance == null) ? StaticFlags : InstanceFlags;
var methodInfo = MethodInfo(methodName, callingType, flags, argumentTypes);
if (methodInfo == null)
{
throw new MissingMethodException(callingType.FullName, methodName);
}
var generic = methodInfo.MakeGenericMethod(genericTypes);
return generic.Invoke(instance, arguments);
}
public static MethodInfo MethodInfo(string methodName, Type callingType, BindingFlags flags,
Type[] argumentTypes)
{
var key = string.Format("{0}.{1}", callingType.GUID, methodName);
var lazy = MethodInfos
.GetOrAdd(key, new Lazy<MethodInfo>(
() => callingType.GetMethod(methodName, flags, null, argumentTypes, null)));
var methodInfo = lazy.Value;
return methodInfo;
}
public static object InvokeStatic(string methodName, Type staticType, Type[] genericTypes,
params object[] arguments)
{
return Invoke(methodName, null, staticType, genericTypes, arguments);
}
public static object InvokeInstance(string methodName, object instance, Type[] genericTypes,
params object[] arguments)
{
return (instance == null) ? null : Invoke(methodName, instance, instance.GetType(), genericTypes, arguments);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment