private static ValueSetter CreateValueSetter(IValueEntry valueEntry) { var entryTypeInfo = ValueEntryTypeInfo.Get(valueEntry.GetType()); var entryType = entryTypeInfo.Type; var entryValueType = entryTypeInfo.RootGenericArguments[1]; var methodInfo = entryType.GetMethod("SetValue", false, false, entryValueType, typeof(bool), typeof(bool)); Assert.IsNotNull(methodInfo); var drawerValueType = typeof(TValue); Assert.IsTrue(entryValueType.IsAssignableFrom(drawerValueType)); var parameterTypes = new[] { typeof(IValueEntry).MakeByRefType(), drawerValueType, typeof(bool), typeof(bool) }; var dynamicMethod = new DynamicMethod( entryType.FullName + ".SetValue", typeof(ValueAccessResult), parameterTypes, entryType); /* Example Implementation: * static ValueAccessResult SetValue(ref IValueEntry valueEntry, * Component value, bool handleErrorLogs, bool catchException) * { * return ((FixedValueEntry<GameObject, Transform>)valueEntry) * .SetValue((Transform)value, handleErrorLogs, catchException); * } */ var gen = dynamicMethod.GetILGenerator(); gen.Emit(OpCodes.Ldarg_0); // 0:entry gen.Emit(OpCodes.Ldind_Ref); gen.Emit(OpCodes.Castclass, entryType); // 0:typedEntry gen.Emit(OpCodes.Ldarg_1); // 0:typedEntry 1:drawerTypeValue gen.EmitTypeCast(drawerValueType, entryValueType); // 0:typedEntry 1:entryValueType gen.Emit(OpCodes.Ldarg_2); // 0:typedEntry 1:entryTypeValue 2:handleErrorLogs gen.Emit(OpCodes.Ldarg_3); // 0:typedEntry 1:entryTypeValue 2:handleErrorLogs 3:catchException gen.Emit(OpCodes.Callvirt, methodInfo); // 0:result gen.Emit(OpCodes.Ret); return((ValueSetter)dynamicMethod.CreateDelegate(typeof(ValueSetter))); }
private static ValueGetter CreateValueGetter(IValueEntry valueEntry) { var entryTypeInfo = ValueEntryTypeInfo.Get(valueEntry.GetType()); var entryType = entryTypeInfo.Type; var entryValueType = entryTypeInfo.RootGenericArguments[1]; var methodInfo = entryType.GetMethod("GetValue", false, false, entryValueType.MakeByRefType(), typeof(bool), typeof(bool)); Assert.IsNotNull(methodInfo); // NOTE: This is a WRONG approach since valueType may different from TValue of current instance. //return (ValueGetter)Delegate.CreateDelegate(typeof(ValueGetter), method); var drawerValueType = typeof(TValue); Assert.IsTrue(entryValueType.IsAssignableFrom(drawerValueType)); var parameterTypes = new[] { typeof(IValueEntry).MakeByRefType(), drawerValueType.MakeByRefType(), typeof(bool), typeof(bool) }; var dynamicMethod = new DynamicMethod( entryType.FullName + ".GetValue", typeof(ValueAccessResult), parameterTypes, entryType); var gen = dynamicMethod.GetILGenerator(); gen.Emit(OpCodes.Ldarg_0); // 0:entry gen.Emit(OpCodes.Ldind_Ref); gen.Emit(OpCodes.Castclass, entryType); // 0:typedEntry if (drawerValueType == entryValueType) { /* Example Implementation: * static ValueAccessResult ViewILGet( * ref IValueEntry valueEntry, out int value, bool handleErrorLogs, bool catchException) * { * return ((FixedValueEntry<GameObject, int>)valueEntry) * .GetValue(out value, handleErrorLogs, catchException); * } */ gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Ldarg_2); gen.Emit(OpCodes.Ldarg_3); gen.Emit(OpCodes.Callvirt, methodInfo); // 0:result } else { /* Example Implementation: * static ValueAccessResult ViewILGet(ref IValueEntry valueEntry, * out Component value, bool handleErrorLogs, bool catchException) * { * Transform entryValue; * var result = ((FixedValueEntry<GameObject, Transform>)valueEntry) * .GetValue(out entryValue, handleErrorLogs, catchException); * value = entryValue; * return result; * } */ var valueInfo = gen.DeclareLocal(entryValueType); //var resultInfo = gen.DeclareLocal(typeof(ValueAccessResult)); gen.Emit(OpCodes.Ldloca_S, valueInfo.LocalIndex); // 0:typedEntry 1:entryValue gen.Emit(OpCodes.Ldarg_2); // 0:typedEntry 1:entryValue 2:handleErrorLogs gen.Emit(OpCodes.Ldarg_3); // 0:typedEntry 1:entryValue 2:handleErrorLogs 3:catchException gen.Emit(OpCodes.Callvirt, methodInfo); // 0:result gen.Emit(OpCodes.Ldarg_1); // 0:result 1:value gen.Emit(OpCodes.Ldloc, valueInfo.LocalIndex); // 0:result 1:value 2:entryValue gen.Emit(OpCodes.Stind_Ref); // value = entryValue 0:result } gen.Emit(OpCodes.Ret); return((ValueGetter)dynamicMethod.CreateDelegate(typeof(ValueGetter))); }