//-----------------------------------------------------------------------
//
// 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
}
}
}