private static Func <object, object> GetCastDelegate(Type from, Type to) { Func <object, object> castDelegate; if (!WeakCastLookup.TryGetInnerValue(from, to, out castDelegate)) { castDelegate = TypeExtensions.GetCastMethodDelegate(from, to); WeakCastLookup.AddInner(from, to, castDelegate); } return(castDelegate); }
private static Func <TFrom, TTo> GetCastDelegate <TFrom, TTo>() { object del; Func <TFrom, TTo> castDelegate; if (!StrongCastLookup.TryGetInnerValue(typeof(TFrom), typeof(TTo), out del)) { castDelegate = TypeExtensions.GetCastMethodDelegate <TFrom, TTo>(); StrongCastLookup.AddInner(typeof(TFrom), typeof(TTo), castDelegate); } else { castDelegate = (Func <TFrom, TTo>)del; } return(castDelegate); }
/// <summary> /// Gets an emitted formatter for a given type. /// <para /> /// NOTE: Some platforms do not support emitting. On such platforms, this method logs an error and returns null. Check whether you can emit on the current platform using <see cref="EmitUtilities.CanEmit"/>. /// </summary> /// <param name="type">The type to emit a formatter for.</param> /// <param name="policy">The serialization policy to use to determine which members the emitted formatter should serialize. If null, <see cref="SerializationPolicies.Strict"/> is used.</param> /// <returns>The type of the emitted formatter.</returns> /// <exception cref="System.ArgumentNullException">The type argument is null.</exception> public static IFormatter GetEmittedFormatter(Type type, ISerializationPolicy policy) { #if !CAN_EMIT Debug.LogError("Cannot use Reflection.Emit on the current platform. The FormatterEmitter class is currently disabled. Check whether emitting is currently possible with EmitUtilities.CanEmit."); return(null); #else if (type == null) { throw new ArgumentNullException("type"); } if (policy == null) { policy = SerializationPolicies.Strict; } IFormatter result = null; if (Formatters.TryGetInnerValue(policy, type, out result) == false) { lock (LOCK) { if (Formatters.TryGetInnerValue(policy, type, out result) == false) { EnsureRuntimeAssembly(); try { result = CreateGenericFormatter(type, runtimeEmittedModule, policy); } catch (Exception ex) { Debug.LogError("The following error occurred while emitting a formatter for the type " + type.Name); Debug.LogException(ex); } Formatters.AddInner(policy, type, result); } } } return(result); #endif }
/// <summary> /// Creates an emitted MonoBehaviour-based <see cref="SerializedProperty"/>. /// </summary> /// <param name="fieldName">Name of the field to emit.</param> /// <param name="valueType">Type of the value to create a property for.</param> /// <param name="targetCount">The target count of the tree to create a property for.</param> /// <param name="gameObject">The game object that the MonoBehaviour of the property is located on.</param> /// <exception cref="System.ArgumentNullException"> /// fieldName is null /// or /// valueType is null /// </exception> /// <exception cref="System.ArgumentException">Target count must be equal to or higher than 1.</exception> public static Handle CreateEmittedMonoBehaviourProperty(string fieldName, Type valueType, int targetCount, ref GameObject gameObject) { DestroyMarkedObjects(); if (fieldName == null) { throw new ArgumentNullException("fieldName"); } if (valueType == null) { throw new ArgumentNullException("valueType"); } if (targetCount < 1) { throw new ArgumentException("Target count must be equal to or higher than 1."); } if (gameObject == null) { gameObject = HostGO; } Type resultType; if (!MonoBehaviourTypeCache.TryGetInnerValue(fieldName, valueType, out resultType)) { resultType = EmitMonoBehaviourType(fieldName, valueType); MonoBehaviourTypeCache.AddInner(fieldName, valueType, resultType); } MonoBehaviour[] targets = new MonoBehaviour[targetCount]; for (int i = 0; i < targetCount; i++) { targets[i] = (MonoBehaviour)gameObject.AddComponent(resultType); targets[i].hideFlags = gameObject.hideFlags; } var serializedObject = new SerializedObject(targets); return(new Handle(serializedObject.FindProperty(fieldName), targets)); }
/// <summary> /// Creates an emitted ScriptableObject-based <see cref="SerializedProperty"/>. /// </summary> /// <param name="fieldName">Name of the field to emit.</param> /// <param name="valueType">Type of the value to create a property for.</param> /// <param name="targetCount">The target count of the tree to create a property for.</param> /// <exception cref="System.ArgumentNullException"> /// fieldName is null /// or /// valueType is null /// </exception> /// <exception cref="System.ArgumentException">Target count must be equal to or higher than 1.</exception> public static SerializedProperty CreateEmittedScriptableObjectProperty(string fieldName, Type valueType, int targetCount) { DestroyMarkedObjects(); if (fieldName == null) { throw new ArgumentNullException("fieldName"); } if (valueType == null) { throw new ArgumentNullException("valueType"); } if (targetCount < 1) { throw new ArgumentException("Target count must be equal to or higher than 1."); } Type resultType; if (PreCreatedScriptableObjectTypes.TryGetValue(valueType, out resultType)) { fieldName = "value"; } else if (!ScriptableObjectTypeCache.TryGetInnerValue(fieldName, valueType, out resultType)) { resultType = EmitScriptableObjectType(fieldName, valueType); ScriptableObjectTypeCache.AddInner(fieldName, valueType, resultType); } ScriptableObject[] targets = new ScriptableObject[targetCount]; for (int i = 0; i < targetCount; i++) { targets[i] = ScriptableObject.CreateInstance(resultType); } var serializedObject = new SerializedObject(targets); return(serializedObject.FindProperty(fieldName)); }
/// <summary> /// Gets a map of all serializable members on the given type. This will also properly map names extracted from <see cref="UnityEngine.Serialization.FormerlySerializedAsAttribute"/> and <see cref="PreviouslySerializedAsAttribute"/> to their corresponding members. /// </summary> /// <param name="type">The type to get a map for.</param> /// <param name="policy">The serialization policy to use. If null, <see cref="SerializationPolicies.Strict"/> is used.</param> /// <returns>A map of all serializable members on the given type.</returns> public static Dictionary <string, MemberInfo> GetSerializableMembersMap(Type type, ISerializationPolicy policy) { Dictionary <string, MemberInfo> result; if (policy == null) { policy = SerializationPolicies.Strict; } lock (LOCK) { if (MemberMapCache.TryGetInnerValue(policy, type, out result) == false) { result = FindSerializableMembersMap(type, policy); MemberMapCache.AddInner(policy, type, result); } } return(result); }
/// <summary> /// Gets an array of all serializable members on the given type. /// </summary> /// <param name="type">The type to get serializable members for.</param> /// <param name="policy">The serialization policy to use. If null, <see cref="SerializationPolicies.Strict"/> is used.</param> /// <returns>An array of all serializable members on the given type.</returns> public static MemberInfo[] GetSerializableMembers(Type type, ISerializationPolicy policy) { MemberInfo[] result; if (policy == null) { policy = SerializationPolicies.Strict; } lock (LOCK) { if (MemberArrayCache.TryGetInnerValue(policy, type, out result) == false) { List <MemberInfo> list = new List <MemberInfo>(); FindSerializableMembers(type, list, policy); result = list.ToArray(); MemberArrayCache.AddInner(policy, type, result); } } return(result); }
private static Func <MemberInfo, bool, IValueGetterSetter> GetEmittedGetterSetterCreator(Type ownerType, Type valueType) { Func <MemberInfo, bool, IValueGetterSetter> result; if (!GetterSetterCreators.TryGetInnerValue(ownerType, valueType, out result)) { var type = typeof(GetterSetter <,>).MakeGenericType(ownerType, valueType); var constructor = type.GetConstructor(GetterSetterConstructorSignature); var method = new DynamicMethod("GetterSetterCreator<" + ownerType.GetNiceName() + ", " + valueType.GetNiceName() + ">", typeof(IValueGetterSetter), new Type[] { typeof(MemberInfo), typeof(bool) }); var il = method.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Newobj, constructor); il.Emit(OpCodes.Ret); result = (Func <MemberInfo, bool, IValueGetterSetter>)method.CreateDelegate(typeof(Func <MemberInfo, bool, IValueGetterSetter>)); GetterSetterCreators.AddInner(ownerType, valueType, result); } return(result); }
/// <summary> /// Gets a formatter for a given type. /// </summary> /// <param name="type">The type to get a formatter for.</param> /// <param name="policy">The serialization policy to use if a formatter has to be emitted. If null, <see cref="SerializationPolicies.Strict"/> is used.</param> /// <returns> /// A formatter for the given type. /// </returns> /// <exception cref="System.ArgumentNullException">The type argument is null.</exception> public static IFormatter GetFormatter(Type type, ISerializationPolicy policy) { if (type == null) { throw new ArgumentNullException("type"); } if (policy == null) { policy = SerializationPolicies.Strict; } IFormatter result; lock (LOCK) { if (TypeFormatterMap.TryGetInnerValue(type, policy, out result) == false) { // System.ExecutionEngineException is marked obsolete in .NET 4.6. // That's all very good for .NET, but Unity still uses it, and that means we use it as well! #pragma warning disable 618 try { result = CreateFormatter(type, policy); } catch (TargetInvocationException ex) { if (ex.GetBaseException() is ExecutionEngineException) { LogAOTError(type, ex.GetBaseException() as ExecutionEngineException); } else { throw ex; } } catch (TypeInitializationException ex) { if (ex.GetBaseException() is ExecutionEngineException) { LogAOTError(type, ex.GetBaseException() as ExecutionEngineException); } else { throw ex; } } catch (ExecutionEngineException ex) { LogAOTError(type, ex); } TypeFormatterMap.AddInner(type, policy, result); #pragma warning restore 618 } } #if UNITY_EDITOR if (OnLocatedFormatter != null) { OnLocatedFormatter(result); } if (OnLocatedEmittableFormatterForType != null && result.GetType().IsGenericType) { #if CAN_EMIT if (result.GetType().GetGenericTypeDefinition() == typeof(FormatterEmitter.RuntimeEmittedFormatter <>)) { OnLocatedEmittableFormatterForType(type); } else #endif if (result.GetType().GetGenericTypeDefinition() == typeof(ReflectionFormatter <>)) { OnLocatedEmittableFormatterForType(type); } } #endif return(result); }