//----------------------------------------------------------------------- // // Copyright (c) 2018 Sirenix IVS // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //----------------------------------------------------------------------- // #if NET_STANDARD_2_0 // #error Odin Inspector is incapable of compiling source code against the .NET Standard 2.0 API surface. You can change the API Compatibility Level in the Player settings. // #endif #if (UNITY_EDITOR || UNITY_STANDALONE) && !ENABLE_IL2CPP && NET_4_6 #define CAN_EMIT #endif namespace VRC.Udon.Serialization.OdinSerializer.Utilities { using System; using System.Reflection; #if CAN_EMIT using System.Reflection.Emit; #endif /// /// Not yet documented. /// public delegate object WeakValueGetter(ref object instance); /// /// Not yet documented. /// public delegate void WeakValueSetter(ref object instance, object value); /// /// Not yet documented. /// public delegate FieldType WeakValueGetter(ref object instance); /// /// Not yet documented. /// public delegate void WeakValueSetter(ref object instance, FieldType value); /// /// Not yet documented. /// public delegate FieldType ValueGetter(ref InstanceType instance); /// /// Not yet documented. /// public delegate void ValueSetter(ref InstanceType instance, FieldType value); /// /// Provides utilities for using the namespace. /// /// This class is due for refactoring. Use at your own peril. /// public static class EmitUtilities { /// /// Gets a value indicating whether emitting is supported on the current platform. /// /// /// true if the current platform can emit; otherwise, false. /// public static bool CanEmit { get { #if CAN_EMIT return true; #else return false; #endif } } /// /// Creates a delegate which gets the value of a field. If emitting is not supported on the current platform, the delegate will use reflection to get the value. /// /// The type of the field to get a value from. /// The instance describing the field to create a getter for. /// A delegate which gets the value of the given field. /// The fieldInfo parameter is null. public static Func CreateStaticFieldGetter(FieldInfo fieldInfo) { if (fieldInfo == null) { throw new ArgumentNullException("fieldInfo"); } if (!fieldInfo.IsStatic) { throw new ArgumentException("Field must be static."); } fieldInfo = fieldInfo.DeAliasField(); if (fieldInfo.IsLiteral) { FieldType value = (FieldType)fieldInfo.GetValue(null); return () => value; } #if !CAN_EMIT // Platform does not support emitting dynamic code return delegate () { return (FieldType)fieldInfo.GetValue(null); }; #else string methodName = fieldInfo.ReflectedType.FullName + ".get_" + fieldInfo.Name; DynamicMethod getterMethod = new DynamicMethod(methodName, typeof(FieldType), new Type[0], true); ILGenerator gen = getterMethod.GetILGenerator(); gen.Emit(OpCodes.Ldsfld, fieldInfo); gen.Emit(OpCodes.Ret); return (Func)getterMethod.CreateDelegate(typeof(Func)); #endif } /// /// Creates a delegate which gets the value of a field. If emitting is not supported on the current platform, the delegate will use reflection to get the value. /// /// The instance describing the field to create a getter for. /// A delegate which gets the value of the given field. /// The fieldInfo parameter is null. public static Func CreateWeakStaticFieldGetter(FieldInfo fieldInfo) { if (fieldInfo == null) { throw new ArgumentNullException("fieldInfo"); } if (!fieldInfo.IsStatic) { throw new ArgumentException("Field must be static."); } fieldInfo = fieldInfo.DeAliasField(); #if !CAN_EMIT // Platform does not support emitting dynamic code return delegate () { return fieldInfo.GetValue(null); }; #else string methodName = fieldInfo.ReflectedType.FullName + ".get_" + fieldInfo.Name; DynamicMethod getterMethod = new DynamicMethod(methodName, typeof(object), new Type[0], true); ILGenerator gen = getterMethod.GetILGenerator(); gen.Emit(OpCodes.Ldsfld, fieldInfo); if (fieldInfo.FieldType.IsValueType) { gen.Emit(OpCodes.Box, fieldInfo.FieldType); } gen.Emit(OpCodes.Ret); return (Func)getterMethod.CreateDelegate(typeof(Func)); #endif } /// /// Creates a delegate which sets the value of a field. If emitting is not supported on the current platform, the delegate will use reflection to set the value. /// /// The type of the field to set a value to. /// The instance describing the field to create a setter for. /// A delegate which sets the value of the given field. /// The fieldInfo parameter is null. public static Action CreateStaticFieldSetter(FieldInfo fieldInfo) { if (fieldInfo == null) { throw new ArgumentNullException("fieldInfo"); } if (!fieldInfo.IsStatic) { throw new ArgumentException("Field must be static."); } fieldInfo = fieldInfo.DeAliasField(); if (fieldInfo.IsLiteral) { throw new ArgumentException("Field cannot be constant."); } #if !CAN_EMIT // Platform does not support emitting dynamic code return delegate (FieldType value) { fieldInfo.SetValue(null, value); }; #else string methodName = fieldInfo.ReflectedType.FullName + ".set_" + fieldInfo.Name; DynamicMethod setterMethod = new DynamicMethod(methodName, null, new Type[] { typeof(FieldType) }, true); ILGenerator gen = setterMethod.GetILGenerator(); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Stsfld, fieldInfo); gen.Emit(OpCodes.Ret); return (Action)setterMethod.CreateDelegate(typeof(Action)); #endif } /// /// Creates a delegate which sets the value of a field. If emitting is not supported on the current platform, the delegate will use reflection to set the value. /// /// The instance describing the field to create a setter for. /// A delegate which sets the value of the given field. /// The fieldInfo parameter is null. public static Action CreateWeakStaticFieldSetter(FieldInfo fieldInfo) { if (fieldInfo == null) { throw new ArgumentNullException("fieldInfo"); } if (!fieldInfo.IsStatic) { throw new ArgumentException("Field must be static."); } fieldInfo = fieldInfo.DeAliasField(); #if !CAN_EMIT // Platform does not support emitting dynamic code return delegate (object value) { fieldInfo.SetValue(null, value); }; #else string methodName = fieldInfo.ReflectedType.FullName + ".set_" + fieldInfo.Name; DynamicMethod setterMethod = new DynamicMethod(methodName, null, new Type[] { typeof(object) }, true); ILGenerator gen = setterMethod.GetILGenerator(); gen.Emit(OpCodes.Ldarg_0); if (fieldInfo.FieldType.IsValueType) { gen.Emit(OpCodes.Unbox_Any, fieldInfo.FieldType); } else { gen.Emit(OpCodes.Castclass, fieldInfo.FieldType); } gen.Emit(OpCodes.Stsfld, fieldInfo); gen.Emit(OpCodes.Ret); return (Action)setterMethod.CreateDelegate(typeof(Action)); #endif } /// /// Creates a delegate which gets the value of a field. If emitting is not supported on the current platform, the delegate will use reflection to get the value. /// /// The type of the instance to get a value from. /// The type of the field to get a value from. /// The instance describing the field to create a getter for. /// A delegate which gets the value of the given field. /// The fieldInfo parameter is null. public static ValueGetter CreateInstanceFieldGetter(FieldInfo fieldInfo) { if (fieldInfo == null) { throw new ArgumentNullException("fieldInfo"); } if (fieldInfo.IsStatic) { throw new ArgumentException("Field cannot be static."); } fieldInfo = fieldInfo.DeAliasField(); #if !CAN_EMIT // Platform does not support emitting dynamic code return delegate (ref InstanceType classInstance) { return (FieldType)fieldInfo.GetValue(classInstance); }; #else string methodName = fieldInfo.ReflectedType.FullName + ".get_" + fieldInfo.Name; DynamicMethod getterMethod = new DynamicMethod(methodName, typeof(FieldType), new Type[1] { typeof(InstanceType).MakeByRefType() }, true); ILGenerator gen = getterMethod.GetILGenerator(); if (typeof(InstanceType).IsValueType) { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldfld, fieldInfo); } else { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldind_Ref); gen.Emit(OpCodes.Ldfld, fieldInfo); } gen.Emit(OpCodes.Ret); return (ValueGetter)getterMethod.CreateDelegate(typeof(ValueGetter)); #endif } /// /// Creates a delegate which gets the value of a field from a weakly typed instance of a given type. If emitting is not supported on the current platform, the delegate will use reflection to get the value. /// /// The type of the field to get a value from. /// The of the instance to get a value from. /// The instance describing the field to create a getter for. /// A delegate which gets the value of the given field. /// The fieldInfo parameter is null. public static WeakValueGetter CreateWeakInstanceFieldGetter(Type instanceType, FieldInfo fieldInfo) { if (fieldInfo == null) { throw new ArgumentNullException("fieldInfo"); } if (instanceType == null) { throw new ArgumentNullException("instanceType"); } if (fieldInfo.IsStatic) { throw new ArgumentException("Field cannot be static."); } fieldInfo = fieldInfo.DeAliasField(); #if !CAN_EMIT // Platform does not support emitting dynamic code return delegate (ref object classInstance) { return (FieldType)fieldInfo.GetValue(classInstance); }; #else string methodName = fieldInfo.ReflectedType.FullName + ".get_" + fieldInfo.Name; DynamicMethod getterMethod = new DynamicMethod(methodName, typeof(FieldType), new Type[1] { typeof(object).MakeByRefType() }, true); ILGenerator gen = getterMethod.GetILGenerator(); if (instanceType.IsValueType) { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldind_Ref); gen.Emit(OpCodes.Unbox_Any, instanceType); gen.Emit(OpCodes.Ldfld, fieldInfo); } else { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldind_Ref); gen.Emit(OpCodes.Castclass, instanceType); gen.Emit(OpCodes.Ldfld, fieldInfo); } gen.Emit(OpCodes.Ret); return (WeakValueGetter)getterMethod.CreateDelegate(typeof(WeakValueGetter)); #endif } /// /// Creates a delegate which gets the weakly typed value of a field from a weakly typed instance of a given type. If emitting is not supported on the current platform, the delegate will use reflection to get the value. /// /// The of the instance to get a value from. /// The instance describing the field to create a getter for. /// A delegate which gets the value of the given field. /// The fieldInfo parameter is null. public static WeakValueGetter CreateWeakInstanceFieldGetter(Type instanceType, FieldInfo fieldInfo) { if (fieldInfo == null) { throw new ArgumentNullException("fieldInfo"); } if (instanceType == null) { throw new ArgumentNullException("instanceType"); } if (fieldInfo.IsStatic) { throw new ArgumentException("Field cannot be static."); } fieldInfo = fieldInfo.DeAliasField(); #if !CAN_EMIT // Platform does not support emitting dynamic code return delegate (ref object classInstance) { return fieldInfo.GetValue(classInstance); }; #else string methodName = fieldInfo.ReflectedType.FullName + ".get_" + fieldInfo.Name; DynamicMethod getterMethod = new DynamicMethod(methodName, typeof(object), new Type[1] { typeof(object).MakeByRefType() }, true); ILGenerator gen = getterMethod.GetILGenerator(); if (instanceType.IsValueType) { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldind_Ref); gen.Emit(OpCodes.Unbox_Any, instanceType); gen.Emit(OpCodes.Ldfld, fieldInfo); if (fieldInfo.FieldType.IsValueType) { gen.Emit(OpCodes.Box, fieldInfo.FieldType); } } else { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldind_Ref); gen.Emit(OpCodes.Castclass, instanceType); gen.Emit(OpCodes.Ldfld, fieldInfo); if (fieldInfo.FieldType.IsValueType) { gen.Emit(OpCodes.Box, fieldInfo.FieldType); } } gen.Emit(OpCodes.Ret); return (WeakValueGetter)getterMethod.CreateDelegate(typeof(WeakValueGetter)); #endif } /// /// Creates a delegate which sets the value of a field. If emitting is not supported on the current platform, the delegate will use reflection to set the value. /// /// The type of the instance to set a value on. /// The type of the field to set a value to. /// The instance describing the field to create a setter for. /// A delegate which sets the value of the given field. /// The fieldInfo parameter is null. public static ValueSetter CreateInstanceFieldSetter(FieldInfo fieldInfo) { if (fieldInfo == null) { throw new ArgumentNullException("fieldInfo"); } if (fieldInfo.IsStatic) { throw new ArgumentException("Field cannot be static."); } fieldInfo = fieldInfo.DeAliasField(); #if !CAN_EMIT // Platform does not support emitting dynamic code return delegate (ref InstanceType classInstance, FieldType value) { if (typeof(InstanceType).IsValueType) { // Box value type so that the value will be properly set via reflection object obj = classInstance; fieldInfo.SetValue(obj, value); // Unbox the boxed value type that was changed classInstance = (InstanceType)obj; } else { fieldInfo.SetValue(classInstance, value); } }; #else string methodName = fieldInfo.ReflectedType.FullName + ".set_" + fieldInfo.Name; DynamicMethod setterMethod = new DynamicMethod(methodName, null, new Type[2] { typeof(InstanceType).MakeByRefType(), typeof(FieldType) }, true); ILGenerator gen = setterMethod.GetILGenerator(); if (typeof(InstanceType).IsValueType) { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Stfld, fieldInfo); } else { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldind_Ref); gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Stfld, fieldInfo); } gen.Emit(OpCodes.Ret); return (ValueSetter)setterMethod.CreateDelegate(typeof(ValueSetter)); #endif } /// /// Creates a delegate which sets the value of a field on a weakly typed instance of a given type. If emitting is not supported on the current platform, the delegate will use reflection to set the value. /// /// The type of the field to set a value to. /// Type of the instance. /// The instance describing the field to create a setter for. /// /// A delegate which sets the value of the given field. /// /// The fieldInfo parameter is null. /// Field cannot be static. public static WeakValueSetter CreateWeakInstanceFieldSetter(Type instanceType, FieldInfo fieldInfo) { if (fieldInfo == null) { throw new ArgumentNullException("fieldInfo"); } if (instanceType == null) { throw new ArgumentNullException("instanceType"); } if (fieldInfo.IsStatic) { throw new ArgumentException("Field cannot be static."); } fieldInfo = fieldInfo.DeAliasField(); #if !CAN_EMIT // Platform does not support emitting dynamic code return delegate (ref object classInstance, FieldType value) { fieldInfo.SetValue(classInstance, value); }; #else string methodName = fieldInfo.ReflectedType.FullName + ".set_" + fieldInfo.Name; DynamicMethod setterMethod = new DynamicMethod(methodName, null, new Type[2] { typeof(object).MakeByRefType(), typeof(FieldType) }, true); ILGenerator gen = setterMethod.GetILGenerator(); if (instanceType.IsValueType) { var local = gen.DeclareLocal(instanceType); gen.Emit(OpCodes.Ldarg_0); // Load object reference argument gen.Emit(OpCodes.Ldind_Ref); // Load reference gen.Emit(OpCodes.Unbox_Any, instanceType); // Unbox to struct gen.Emit(OpCodes.Stloc, local); // Set local to struct value gen.Emit(OpCodes.Ldloca_S, local); // Load address to local value gen.Emit(OpCodes.Ldarg_1); // Load FieldType value gen.Emit(OpCodes.Stfld, fieldInfo); // Set field on local struct value gen.Emit(OpCodes.Ldarg_0); // Load object reference argument gen.Emit(OpCodes.Ldloc, local); // Load local struct value gen.Emit(OpCodes.Box, instanceType); // Box local struct gen.Emit(OpCodes.Stind_Ref); // Set object reference argument } else { gen.Emit(OpCodes.Ldarg_0); // Load object reference argument gen.Emit(OpCodes.Ldind_Ref); // Load reference gen.Emit(OpCodes.Castclass, instanceType); // Cast to instance type gen.Emit(OpCodes.Ldarg_1); // Load value argument gen.Emit(OpCodes.Stfld, fieldInfo); // Set field } gen.Emit(OpCodes.Ret); return (WeakValueSetter)setterMethod.CreateDelegate(typeof(WeakValueSetter)); #endif } /// /// Creates a delegate which sets the weakly typed value of a field on a weakly typed instance of a given type. If emitting is not supported on the current platform, the delegate will use reflection to set the value. /// /// Type of the instance. /// The instance describing the field to create a setter for. /// /// A delegate which sets the value of the given field. /// /// The fieldInfo parameter is null. /// Field cannot be static. public static WeakValueSetter CreateWeakInstanceFieldSetter(Type instanceType, FieldInfo fieldInfo) { if (fieldInfo == null) { throw new ArgumentNullException("fieldInfo"); } if (instanceType == null) { throw new ArgumentNullException("instanceType"); } if (fieldInfo.IsStatic) { throw new ArgumentException("Field cannot be static."); } fieldInfo = fieldInfo.DeAliasField(); #if !CAN_EMIT // Platform does not support emitting dynamic code return delegate (ref object classInstance, object value) { fieldInfo.SetValue(classInstance, value); }; #else string methodName = fieldInfo.ReflectedType.FullName + ".set_" + fieldInfo.Name; DynamicMethod setterMethod = new DynamicMethod(methodName, null, new Type[2] { typeof(object).MakeByRefType(), typeof(object) }, true); ILGenerator gen = setterMethod.GetILGenerator(); if (instanceType.IsValueType) { var local = gen.DeclareLocal(instanceType); gen.Emit(OpCodes.Ldarg_0); // Load object reference argument gen.Emit(OpCodes.Ldind_Ref); // Load reference gen.Emit(OpCodes.Unbox_Any, instanceType); // Unbox to struct gen.Emit(OpCodes.Stloc, local); // Set local to struct value gen.Emit(OpCodes.Ldloca_S, local); // Load address to local value gen.Emit(OpCodes.Ldarg_1); // Load FieldType value if (fieldInfo.FieldType.IsValueType) { gen.Emit(OpCodes.Unbox_Any, fieldInfo.FieldType); } else { gen.Emit(OpCodes.Castclass, fieldInfo.FieldType); } gen.Emit(OpCodes.Stfld, fieldInfo); // Set field on local struct value gen.Emit(OpCodes.Ldarg_0); // Load object reference argument gen.Emit(OpCodes.Ldloc, local); // Load local struct value gen.Emit(OpCodes.Box, instanceType); // Box local struct gen.Emit(OpCodes.Stind_Ref); // Set object reference argument } else { gen.Emit(OpCodes.Ldarg_0); // Load object reference argument gen.Emit(OpCodes.Ldind_Ref); // Load reference gen.Emit(OpCodes.Castclass, instanceType); // Cast to instance type gen.Emit(OpCodes.Ldarg_1); // Load value argument if (fieldInfo.FieldType.IsValueType) { gen.Emit(OpCodes.Unbox_Any, fieldInfo.FieldType); } else { gen.Emit(OpCodes.Castclass, fieldInfo.FieldType); } gen.Emit(OpCodes.Stfld, fieldInfo); // Set field } gen.Emit(OpCodes.Ret); return (WeakValueSetter)setterMethod.CreateDelegate(typeof(WeakValueSetter)); #endif } /// /// Creates a delegate which gets the weakly typed value of a field from a weakly typed instance of a given type. If emitting is not supported on the current platform, the delegate will use reflection to get the value. /// /// The of the instance to get a value from. /// The instance describing the field to create a getter for. /// A delegate which gets the value of the given field. /// The fieldInfo parameter is null. public static WeakValueGetter CreateWeakInstancePropertyGetter(Type instanceType, PropertyInfo propertyInfo) { if (propertyInfo == null) { throw new ArgumentNullException("propertyInfo"); } if (instanceType == null) { throw new ArgumentNullException("instanceType"); } propertyInfo = propertyInfo.DeAliasProperty(); if (propertyInfo.GetIndexParameters().Length > 0) { throw new ArgumentException("Property must not have any index parameters"); } var getMethod = propertyInfo.GetGetMethod(true); if (getMethod == null) { throw new ArgumentException("Property must have a getter."); } if (getMethod.IsStatic) { throw new ArgumentException("Property cannot be static."); } #if !CAN_EMIT // Platform does not support emitting dynamic code return delegate (ref object classInstance) { return propertyInfo.GetValue(classInstance, null); }; #else string methodName = propertyInfo.ReflectedType.FullName + ".get_" + propertyInfo.Name; DynamicMethod getterMethod = new DynamicMethod(methodName, typeof(object), new Type[1] { typeof(object).MakeByRefType() }, true); ILGenerator gen = getterMethod.GetILGenerator(); if (instanceType.IsValueType) { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldind_Ref); gen.Emit(OpCodes.Unbox_Any, instanceType); if (getMethod.IsVirtual || getMethod.IsAbstract) { gen.Emit(OpCodes.Callvirt, getMethod); } else { gen.Emit(OpCodes.Call, getMethod); } if (propertyInfo.PropertyType.IsValueType) { gen.Emit(OpCodes.Box, propertyInfo.PropertyType); } } else { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldind_Ref); gen.Emit(OpCodes.Castclass, instanceType); if (getMethod.IsVirtual || getMethod.IsAbstract) { gen.Emit(OpCodes.Callvirt, getMethod); } else { gen.Emit(OpCodes.Call, getMethod); } if (propertyInfo.PropertyType.IsValueType) { gen.Emit(OpCodes.Box, propertyInfo.PropertyType); } } gen.Emit(OpCodes.Ret); return (WeakValueGetter)getterMethod.CreateDelegate(typeof(WeakValueGetter)); #endif } /// /// Creates a delegate which sets the weakly typed value of a property on a weakly typed instance of a given type. If emitting is not supported on the current platform, the delegate will use reflection to set the value. /// /// Type of the instance. /// The instance describing the property to create a setter for. /// /// A delegate which sets the value of the given field. /// /// The fieldInfo parameter is null. /// Property cannot be static. public static WeakValueSetter CreateWeakInstancePropertySetter(Type instanceType, PropertyInfo propertyInfo) { if (propertyInfo == null) { throw new ArgumentNullException("propertyInfo"); } if (instanceType == null) { throw new ArgumentNullException("instanceType"); } propertyInfo = propertyInfo.DeAliasProperty(); if (propertyInfo.GetIndexParameters().Length > 0) { throw new ArgumentException("Property must not have any index parameters"); } var setMethod = propertyInfo.GetSetMethod(true); if (setMethod.IsStatic) { throw new ArgumentException("Property cannot be static."); } #if !CAN_EMIT // Platform does not support emitting dynamic code return delegate (ref object classInstance, object value) { propertyInfo.SetValue(classInstance, value, null); }; #else string methodName = propertyInfo.ReflectedType.FullName + ".set_" + propertyInfo.Name; DynamicMethod setterMethod = new DynamicMethod(methodName, null, new Type[2] { typeof(object).MakeByRefType(), typeof(object) }, true); ILGenerator gen = setterMethod.GetILGenerator(); if (instanceType.IsValueType) { var local = gen.DeclareLocal(instanceType); gen.Emit(OpCodes.Ldarg_0); // Load object reference argument gen.Emit(OpCodes.Ldind_Ref); // Load reference gen.Emit(OpCodes.Unbox_Any, instanceType); // Unbox to struct gen.Emit(OpCodes.Stloc, local); // Set local to struct value gen.Emit(OpCodes.Ldloca_S, local); // Load address to local value gen.Emit(OpCodes.Ldarg_1); // Load PropertyInfo value if (propertyInfo.PropertyType.IsValueType) { gen.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType); } else { gen.Emit(OpCodes.Castclass, propertyInfo.PropertyType); } if (setMethod.IsVirtual || setMethod.IsAbstract) { gen.Emit(OpCodes.Callvirt, setMethod); // Set property on local struct value } else { gen.Emit(OpCodes.Call, setMethod); // Set property on local struct value } gen.Emit(OpCodes.Ldarg_0); // Load object reference argument gen.Emit(OpCodes.Ldloc, local); // Load local struct value gen.Emit(OpCodes.Box, instanceType); // Box local struct gen.Emit(OpCodes.Stind_Ref); // Set object reference argument } else { gen.Emit(OpCodes.Ldarg_0); // Load object reference argument gen.Emit(OpCodes.Ldind_Ref); // Load reference gen.Emit(OpCodes.Castclass, instanceType); // Cast to instance type gen.Emit(OpCodes.Ldarg_1); // Load value argument if (propertyInfo.PropertyType.IsValueType) { gen.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType); } else { gen.Emit(OpCodes.Castclass, propertyInfo.PropertyType); } if (setMethod.IsVirtual || setMethod.IsAbstract) { gen.Emit(OpCodes.Callvirt, setMethod); // Set property on local struct value } else { gen.Emit(OpCodes.Call, setMethod); // Set property on local struct value } } gen.Emit(OpCodes.Ret); return (WeakValueSetter)setterMethod.CreateDelegate(typeof(WeakValueSetter)); #endif } /// /// Creates a delegate which sets the value of a property. If emitting is not supported on the current platform, the delegate will use reflection to set the value. /// /// The type of the property to set a value to. /// The instance describing the property to create a setter for. /// A delegate which sets the value of the given property. /// The propertyInfo parameter is null. public static Action CreateStaticPropertySetter(PropertyInfo propertyInfo) { if (propertyInfo == null) { throw new ArgumentNullException("fieldInfo"); } propertyInfo = propertyInfo.DeAliasProperty(); if (propertyInfo.GetIndexParameters().Length > 0) { throw new ArgumentException("Property must not have any index parameters"); } MethodInfo setMethod = propertyInfo.GetSetMethod(true); if (setMethod == null) { throw new ArgumentException("Property must have a set method."); } if (!setMethod.IsStatic) { throw new ArgumentException("Property must be static."); } #if !CAN_EMIT // Platform does not support emitting dynamic code return delegate (PropType value) { propertyInfo.SetValue(null, value, null); }; #else string methodName = propertyInfo.ReflectedType.FullName + ".set_" + propertyInfo.Name; DynamicMethod setterMethod = new DynamicMethod(methodName, null, new Type[] { typeof(PropType) }, true); ILGenerator gen = setterMethod.GetILGenerator(); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Call, setMethod); gen.Emit(OpCodes.Ret); return (Action)setterMethod.CreateDelegate(typeof(Action)); #endif } /// /// Creates a delegate which gets the value of a property. If emitting is not supported on the current platform, the delegate will use reflection to get the value. /// /// The type of the property to get a value from. /// The instance describing the property to create a getter for. /// A delegate which gets the value of the given property. /// The propertyInfo parameter is null. public static Func CreateStaticPropertyGetter(PropertyInfo propertyInfo) { if (propertyInfo == null) { throw new ArgumentNullException("propertyInfo"); } propertyInfo = propertyInfo.DeAliasProperty(); if (propertyInfo.GetIndexParameters().Length > 0) { throw new ArgumentException("Property must not have any index parameters"); } MethodInfo getMethod = propertyInfo.GetGetMethod(true); if (getMethod == null) { throw new ArgumentException("Property must have a get method."); } if (!getMethod.IsStatic) { throw new ArgumentException("Property must be static."); } #if !CAN_EMIT // Platform does not support emitting dynamic code return delegate () { return (PropType)propertyInfo.GetValue(null, null); }; #else string methodName = propertyInfo.ReflectedType.FullName + ".get_" + propertyInfo.Name; DynamicMethod getterMethod = new DynamicMethod(methodName, typeof(PropType), new Type[0], true); ILGenerator gen = getterMethod.GetILGenerator(); gen.Emit(OpCodes.Call, getMethod); var returnType = propertyInfo.GetReturnType(); if (returnType.IsValueType && !typeof(PropType).IsValueType) { gen.Emit(OpCodes.Box, returnType); } gen.Emit(OpCodes.Ret); return (Func)getterMethod.CreateDelegate(typeof(Func)); #endif } /// /// Creates a delegate which sets the value of a property. If emitting is not supported on the current platform, the delegate will use reflection to set the value. /// /// The type of the instance to set a value on. /// The type of the property to set a value to. /// The instance describing the property to create a setter for. /// A delegate which sets the value of the given property. /// The propertyInfo parameter is null. public static ValueSetter CreateInstancePropertySetter(PropertyInfo propertyInfo) { if (propertyInfo == null) { throw new ArgumentNullException("fieldInfo"); } propertyInfo = propertyInfo.DeAliasProperty(); if (propertyInfo.GetIndexParameters().Length > 0) { throw new ArgumentException("Property must not have any index parameters"); } MethodInfo setMethod = propertyInfo.GetSetMethod(true); if (setMethod == null) { throw new ArgumentException("Property must have a set method."); } if (setMethod.IsStatic) { throw new ArgumentException("Property cannot be static."); } #if !CAN_EMIT // Platform does not support emitting dynamic code return delegate (ref InstanceType classInstance, PropType value) { if (typeof(InstanceType).IsValueType) { // Box value type so that the value will be properly set via reflection object obj = classInstance; propertyInfo.SetValue(obj, value, null); // Unbox the boxed value type that was changed classInstance = (InstanceType)obj; } else { propertyInfo.SetValue(classInstance, value, null); } }; #else string methodName = propertyInfo.ReflectedType.FullName + ".set_" + propertyInfo.Name; DynamicMethod setterMethod = new DynamicMethod(methodName, null, new Type[2] { typeof(InstanceType).MakeByRefType(), typeof(PropType) }, true); ILGenerator gen = setterMethod.GetILGenerator(); if (typeof(InstanceType).IsValueType) { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Callvirt, setMethod); } else { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldind_Ref); gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Callvirt, setMethod); } gen.Emit(OpCodes.Ret); return (ValueSetter)setterMethod.CreateDelegate(typeof(ValueSetter)); #endif } /// /// Creates a delegate which gets the value of a property. If emitting is not supported on the current platform, the delegate will use reflection to get the value. /// /// The type of the instance to get a value from. /// The type of the property to get a value from. /// The instance describing the property to create a getter for. /// A delegate which gets the value of the given property. /// The propertyInfo parameter is null. public static ValueGetter CreateInstancePropertyGetter(PropertyInfo propertyInfo) { if (propertyInfo == null) { throw new ArgumentNullException("propertyInfo"); } propertyInfo = propertyInfo.DeAliasProperty(); if (propertyInfo.GetIndexParameters().Length > 0) { throw new ArgumentException("Property must not have any index parameters"); } MethodInfo getMethod = propertyInfo.GetGetMethod(true); if (getMethod == null) { throw new ArgumentException("Property must have a get method."); } if (getMethod.IsStatic) { throw new ArgumentException("Property cannot be static."); } #if !CAN_EMIT // Platform does not support emitting dynamic code return delegate (ref InstanceType classInstance) { return (PropType)propertyInfo.GetValue(classInstance, null); }; #else string methodName = propertyInfo.ReflectedType.FullName + ".get_" + propertyInfo.Name; DynamicMethod getterMethod = new DynamicMethod(methodName, typeof(PropType), new Type[] { typeof(InstanceType).MakeByRefType() }, true); ILGenerator gen = getterMethod.GetILGenerator(); if (typeof(InstanceType).IsValueType) { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Callvirt, getMethod); } else { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldind_Ref); gen.Emit(OpCodes.Callvirt, getMethod); } gen.Emit(OpCodes.Ret); return (ValueGetter)getterMethod.CreateDelegate(typeof(ValueGetter)); #endif } /// /// Creates a fast delegate method which calls a given parameterless instance method and returns the result. /// /// The type of the class which the method is on. /// The type which is returned by the given method info. /// The method info instance which is used. /// A delegate which calls the method and returns the result, except it's hundreds of times faster than MethodInfo.Invoke. public static Func CreateMethodReturner(MethodInfo methodInfo) { if (methodInfo == null) { throw new ArgumentNullException("methodInfo"); } if (methodInfo.IsStatic) { throw new ArgumentException("Given method '" + methodInfo.Name + "' is static when it has to be an instance method."); } methodInfo = methodInfo.DeAliasMethod(); // Luckily there's no need to emit this - we can just create a delegate and it's only ~10% slower than calling the method directly // from normal compiled/emitted code. As opposed to using MethodInfo.Invoke, which is on average 600 (!!!) times slower. return (Func)Delegate.CreateDelegate(typeof(Func), methodInfo); } /// /// Creates a fast delegate method which calls a given parameterless static method. /// /// The method info instance which is used. /// A delegate which calls the method and returns the result, except it's hundreds of times faster than MethodInfo.Invoke. public static Action CreateStaticMethodCaller(MethodInfo methodInfo) { if (methodInfo == null) { throw new ArgumentNullException("methodInfo"); } if (!methodInfo.IsStatic) { throw new ArgumentException("Given method '" + methodInfo.Name + "' is an instance method when it has to be static."); } if (methodInfo.GetParameters().Length > 0) { throw new ArgumentException("Given method cannot have any parameters."); } methodInfo = methodInfo.DeAliasMethod(); // Luckily there's no need to emit this - we can just create a delegate and it's only ~10% slower than calling the method directly // from normal compiled/emitted code. As opposed to using MethodInfo.Invoke, which is on average 600 (!!!) times slower. return (Action)Delegate.CreateDelegate(typeof(Action), methodInfo); } /// /// Creates a fast delegate method which calls a given parameterless weakly typed instance method. /// /// The method info instance which is used. /// A delegate which calls the method and returns the result, except it's hundreds of times faster than MethodInfo.Invoke. public static Action CreateWeakInstanceMethodCaller(MethodInfo methodInfo) { if (methodInfo == null) { throw new ArgumentNullException("methodInfo"); } if (methodInfo.IsStatic) { throw new ArgumentException("Given method '" + methodInfo.Name + "' is static when it has to be an instance method."); } var parameters = methodInfo.GetParameters(); if (parameters.Length != 1) { throw new ArgumentException("Given method '" + methodInfo.Name + "' must have exactly one parameter."); } if (parameters[0].ParameterType != typeof(TArg1)) { throw new ArgumentException("The first parameter of the method '" + methodInfo.Name + "' must be of type " + typeof(TArg1) + "."); } methodInfo = methodInfo.DeAliasMethod(); #if !CAN_EMIT // Platform does not support emitting dynamic code return (object classInstance, TArg1 arg) => { methodInfo.Invoke(classInstance, new object[] { arg }); }; #else Type declaringType = methodInfo.DeclaringType; string methodName = methodInfo.ReflectedType.FullName + ".call_" + methodInfo.Name; DynamicMethod method = new DynamicMethod(methodName, null, new Type[] { typeof(object), typeof(TArg1) }, true); ILGenerator gen = method.GetILGenerator(); if (declaringType.IsValueType) { var loc = gen.DeclareLocal(declaringType); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Unbox_Any, declaringType); gen.Emit(OpCodes.Stloc, loc); gen.Emit(OpCodes.Ldloca_S, loc); gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Call, methodInfo); } else { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Castclass, declaringType); gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Callvirt, methodInfo); } gen.Emit(OpCodes.Ret); return (Action)method.CreateDelegate(typeof(Action)); #endif } /// /// Not yet documented. /// public static Action CreateWeakInstanceMethodCaller(MethodInfo methodInfo) { if (methodInfo == null) { throw new ArgumentNullException("methodInfo"); } if (methodInfo.IsStatic) { throw new ArgumentException("Given method '" + methodInfo.Name + "' is static when it has to be an instance method."); } if (methodInfo.GetParameters().Length > 0) { throw new ArgumentException("Given method cannot have any parameters."); } methodInfo = methodInfo.DeAliasMethod(); #if !CAN_EMIT // Platform does not support emitting dynamic code return delegate (object classInstance) { methodInfo.Invoke(classInstance, null); }; #else Type declaringType = methodInfo.DeclaringType; string methodName = methodInfo.ReflectedType.FullName + ".call_" + methodInfo.Name; DynamicMethod method = new DynamicMethod(methodName, null, new Type[] { typeof(object) }, true); ILGenerator gen = method.GetILGenerator(); if (declaringType.IsValueType) { var loc = gen.DeclareLocal(declaringType); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Unbox_Any, declaringType); gen.Emit(OpCodes.Stloc, loc); gen.Emit(OpCodes.Ldloca_S, loc); gen.Emit(OpCodes.Call, methodInfo); } else { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Castclass, declaringType); gen.Emit(OpCodes.Callvirt, methodInfo); } if (methodInfo.ReturnType != null && methodInfo.ReturnType != typeof(void)) { // If there is a return type, pop the returned value off the stack, because we're not returning anything gen.Emit(OpCodes.Pop); } gen.Emit(OpCodes.Ret); return (Action)method.CreateDelegate(typeof(Action)); #endif } /// /// Creates a fast delegate method which calls a given weakly typed instance method with one argument and returns a value. /// /// The type of the result. /// The type of the first argument. /// The method info instance which is used. /// /// A delegate which calls the method and returns the result, except it's hundreds of times faster than MethodInfo.Invoke. /// /// methodInfo /// /// Given method ' + methodInfo.Name + ' is static when it has to be an instance method. /// or /// Given method ' + methodInfo.Name + ' must return type + typeof(TResult) + . /// or /// Given method ' + methodInfo.Name + ' must have exactly one parameter. /// or /// The first parameter of the method ' + methodInfo.Name + ' must be of type + typeof(TArg1) + . /// public static Func CreateWeakInstanceMethodCaller(MethodInfo methodInfo) { if (methodInfo == null) { throw new ArgumentNullException("methodInfo"); } if (methodInfo.IsStatic) { throw new ArgumentException("Given method '" + methodInfo.Name + "' is static when it has to be an instance method."); } if (methodInfo.ReturnType != typeof(TResult)) { throw new ArgumentException("Given method '" + methodInfo.Name + "' must return type " + typeof(TResult) + "."); } var parameters = methodInfo.GetParameters(); if (parameters.Length != 1) { throw new ArgumentException("Given method '" + methodInfo.Name + "' must have exactly one parameter."); } if (typeof(TArg1).InheritsFrom(parameters[0].ParameterType) == false) { throw new ArgumentException("The first parameter of the method '" + methodInfo.Name + "' must be of type " + typeof(TArg1) + "."); } methodInfo = methodInfo.DeAliasMethod(); #if !CAN_EMIT // Platform does not support emitting dynamic code return (object classInstance, TArg1 arg1) => { return (TResult)methodInfo.Invoke(classInstance, new object[] { arg1 }); }; #else Type declaringType = methodInfo.DeclaringType; string methodName = methodInfo.ReflectedType.FullName + ".call_" + methodInfo.Name; DynamicMethod method = new DynamicMethod(methodName, typeof(TResult), new Type[] { typeof(object), typeof(TArg1) }, true); ILGenerator gen = method.GetILGenerator(); if (declaringType.IsValueType) { var loc = gen.DeclareLocal(declaringType); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Unbox_Any, declaringType); gen.Emit(OpCodes.Stloc, loc); gen.Emit(OpCodes.Ldloca_S, loc); gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Call, methodInfo); } else { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Castclass, declaringType); gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Callvirt, methodInfo); } gen.Emit(OpCodes.Ret); return (Func)method.CreateDelegate(typeof(Func)); #endif } /// /// Not yet documented. /// public static Func CreateWeakInstanceMethodCallerFunc(MethodInfo methodInfo) { if (methodInfo == null) { throw new ArgumentNullException("methodInfo"); } if (methodInfo.IsStatic) { throw new ArgumentException("Given method '" + methodInfo.Name + "' is static when it has to be an instance method."); } if (methodInfo.ReturnType != typeof(TResult)) { throw new ArgumentException("Given method '" + methodInfo.Name + "' must return type " + typeof(TResult) + "."); } var parameters = methodInfo.GetParameters(); if (parameters.Length != 0) { throw new ArgumentException("Given method '" + methodInfo.Name + "' must have no parameter."); } methodInfo = methodInfo.DeAliasMethod(); #if !CAN_EMIT // Platform does not support emitting dynamic code return (object classInstance) => { return (TResult)methodInfo.Invoke(classInstance, null); }; #else Type declaringType = methodInfo.DeclaringType; string methodName = methodInfo.ReflectedType.FullName + ".call_" + methodInfo.Name; DynamicMethod method = new DynamicMethod(methodName, typeof(TResult), new Type[] { typeof(object) }, true); ILGenerator gen = method.GetILGenerator(); if (declaringType.IsValueType) { var loc = gen.DeclareLocal(declaringType); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Unbox_Any, declaringType); gen.Emit(OpCodes.Stloc, loc); gen.Emit(OpCodes.Ldloca_S, loc); gen.Emit(OpCodes.Call, methodInfo); } else { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Castclass, declaringType); gen.Emit(OpCodes.Callvirt, methodInfo); } gen.Emit(OpCodes.Ret); return (Func)method.CreateDelegate(typeof(Func)); #endif } /// /// Not yet documented. /// public static Func CreateWeakInstanceMethodCallerFunc(MethodInfo methodInfo) { if (methodInfo == null) { throw new ArgumentNullException("methodInfo"); } if (methodInfo.IsStatic) { throw new ArgumentException("Given method '" + methodInfo.Name + "' is static when it has to be an instance method."); } if (methodInfo.ReturnType != typeof(TResult)) { throw new ArgumentException("Given method '" + methodInfo.Name + "' must return type " + typeof(TResult) + "."); } var parameters = methodInfo.GetParameters(); if (parameters.Length != 1) { throw new ArgumentException("Given method '" + methodInfo.Name + "' must have one parameter."); } if (!parameters[0].ParameterType.IsAssignableFrom(typeof(TArg))) { throw new ArgumentException("Given method '" + methodInfo.Name + "' has an invalid parameter type."); } methodInfo = methodInfo.DeAliasMethod(); #if !CAN_EMIT // Platform does not support emitting dynamic code return (object classInstance, TArg arg) => { return (TResult)methodInfo.Invoke(classInstance, new object[] { arg }); }; #else Type declaringType = methodInfo.DeclaringType; string methodName = methodInfo.ReflectedType.FullName + ".call_" + methodInfo.Name; DynamicMethod method = new DynamicMethod(methodName, typeof(TResult), new Type[] { typeof(object), typeof(TArg) }, true); ILGenerator gen = method.GetILGenerator(); if (declaringType.IsValueType) { var loc = gen.DeclareLocal(declaringType); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Unbox_Any, declaringType); gen.Emit(OpCodes.Stloc, loc); gen.Emit(OpCodes.Ldloca_S, loc); gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Call, methodInfo); } else { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Castclass, declaringType); gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Callvirt, methodInfo); } gen.Emit(OpCodes.Ret); return (Func)method.CreateDelegate(typeof(Func)); #endif } /// /// Creates a fast delegate method which calls a given parameterless instance method on a reference type. /// /// The type of the class which the method is on. /// The method info instance which is used. /// A delegate which calls the method and returns the result, except it's hundreds of times faster than MethodInfo.Invoke. public static Action CreateInstanceMethodCaller(MethodInfo methodInfo) { if (methodInfo == null) { throw new ArgumentNullException("methodInfo"); } if (methodInfo.IsStatic) { throw new ArgumentException("Given method '" + methodInfo.Name + "' is static when it has to be an instance method."); } if (methodInfo.GetParameters().Length > 0) { throw new ArgumentException("Given method cannot have any parameters."); } if (typeof(InstanceType).IsValueType) { throw new ArgumentException("This method does not work with struct instances; please use CreateInstanceRefMethodCaller instead."); } methodInfo = methodInfo.DeAliasMethod(); // Luckily there's no need to emit this - we can just create a delegate and it's only ~10% slower than calling the method directly // from normal compiled/emitted code. As opposed to using MethodInfo.Invoke, which is on average 600 (!!!) times slower. return (Action)Delegate.CreateDelegate(typeof(Action), methodInfo); } /// /// Creates a fast delegate method which calls a given instance method with a given argument on a reference type. /// /// The type of the class which the method is on. /// The type of the argument with which to call the method. /// The method info instance which is used. /// A delegate which calls the method and returns the result, except it's hundreds of times faster than MethodInfo.Invoke. public static Action CreateInstanceMethodCaller(MethodInfo methodInfo) { if (methodInfo == null) { throw new ArgumentNullException("methodInfo"); } if (methodInfo.IsStatic) { throw new ArgumentException("Given method '" + methodInfo.Name + "' is static when it has to be an instance method."); } if (methodInfo.GetParameters().Length != 1) { throw new ArgumentException("Given method must have only one parameter."); } if (typeof(InstanceType).IsValueType) { throw new ArgumentException("This method does not work with struct instances; please use CreateInstanceRefMethodCaller instead."); } methodInfo = methodInfo.DeAliasMethod(); // Luckily there's no need to emit this - we can just create a delegate and it's only ~10% slower than calling the method directly // from normal compiled/emitted code. As opposed to using MethodInfo.Invoke, which is on average 600 (!!!) times slower. return (Action)Delegate.CreateDelegate(typeof(Action), methodInfo); } public delegate void InstanceRefMethodCaller(ref InstanceType instance); public delegate void InstanceRefMethodCaller(ref InstanceType instance, TArg1 arg1); /// /// Creates a fast delegate method which calls a given parameterless instance method. /// /// The type of the class which the method is on. /// The method info instance which is used. /// A delegate which calls the method and returns the result, except it's hundreds of times faster than MethodInfo.Invoke. public static InstanceRefMethodCaller CreateInstanceRefMethodCaller(MethodInfo methodInfo) { if (methodInfo == null) { throw new ArgumentNullException("methodInfo"); } if (methodInfo.IsStatic) { throw new ArgumentException("Given method '" + methodInfo.Name + "' is static when it has to be an instance method."); } if (methodInfo.GetParameters().Length > 0) { throw new ArgumentException("Given method cannot have any parameters."); } methodInfo = methodInfo.DeAliasMethod(); #if !CAN_EMIT // Platform does not support emitting dynamic code return (ref InstanceType instance) => { object obj = instance; methodInfo.Invoke(obj, null); instance = (InstanceType)obj; }; #else Type declaringType = methodInfo.DeclaringType; string methodName = methodInfo.ReflectedType.FullName + ".call_" + methodInfo.Name; DynamicMethod method = new DynamicMethod(methodName, typeof(void), new Type[] { typeof(InstanceType).MakeByRefType() }, true); ILGenerator gen = method.GetILGenerator(); if (declaringType.IsValueType) { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Call, methodInfo); } else { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldind_Ref); gen.Emit(OpCodes.Callvirt, methodInfo); } gen.Emit(OpCodes.Ret); return (InstanceRefMethodCaller)method.CreateDelegate(typeof(InstanceRefMethodCaller)); #endif } /// /// Creates a fast delegate method which calls a given instance method with a given argument on a struct type. /// /// The type of the class which the method is on. /// The type of the argument with which to call the method. /// The method info instance which is used. /// A delegate which calls the method and returns the result, except it's hundreds of times faster than MethodInfo.Invoke. public static InstanceRefMethodCaller CreateInstanceRefMethodCaller(MethodInfo methodInfo) { if (methodInfo == null) { throw new ArgumentNullException("methodInfo"); } if (methodInfo.IsStatic) { throw new ArgumentException("Given method '" + methodInfo.Name + "' is static when it has to be an instance method."); } if (methodInfo.GetParameters().Length != 1) { throw new ArgumentException("Given method must have only one parameter."); } methodInfo = methodInfo.DeAliasMethod(); #if !CAN_EMIT // Platform does not support emitting dynamic code return (ref InstanceType instance, Arg1 arg1) => { object obj = instance; methodInfo.Invoke(obj, new object[] { arg1 }); instance = (InstanceType)obj; }; #else Type declaringType = methodInfo.DeclaringType; string methodName = methodInfo.ReflectedType.FullName + ".call_" + methodInfo.Name; DynamicMethod method = new DynamicMethod(methodName, typeof(void), new Type[] { typeof(InstanceType).MakeByRefType(), typeof(Arg1) }, true); ILGenerator gen = method.GetILGenerator(); if (declaringType.IsValueType) { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Call, methodInfo); } else { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldind_Ref); gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Callvirt, methodInfo); } gen.Emit(OpCodes.Ret); return (InstanceRefMethodCaller)method.CreateDelegate(typeof(InstanceRefMethodCaller)); #endif } } }