diff options
author | Shockah <me@shockah.pl> | 2022-02-10 11:43:35 +0100 |
---|---|---|
committer | Shockah <me@shockah.pl> | 2022-02-10 11:43:35 +0100 |
commit | 07259452170a253c44d5c2be68fc2342a88d2504 (patch) | |
tree | bb8b4c634db71f5b1f5c7e14539c58954aed9356 /src/SMAPI/Framework/Reflection | |
parent | 61415e41eb8f5f61e8b241255162257191c0a766 (diff) | |
download | SMAPI-07259452170a253c44d5c2be68fc2342a88d2504.tar.gz SMAPI-07259452170a253c44d5c2be68fc2342a88d2504.tar.bz2 SMAPI-07259452170a253c44d5c2be68fc2342a88d2504.zip |
add proxy instance caching
Diffstat (limited to 'src/SMAPI/Framework/Reflection')
-rw-r--r-- | src/SMAPI/Framework/Reflection/InterfaceProxyBuilder.cs | 18 | ||||
-rw-r--r-- | src/SMAPI/Framework/Reflection/InterfaceProxyFactory.cs | 2 | ||||
-rw-r--r-- | src/SMAPI/Framework/Reflection/InterfaceProxyGlue.cs | 6 |
3 files changed, 17 insertions, 9 deletions
diff --git a/src/SMAPI/Framework/Reflection/InterfaceProxyBuilder.cs b/src/SMAPI/Framework/Reflection/InterfaceProxyBuilder.cs index 49cc6bca..63a594fa 100644 --- a/src/SMAPI/Framework/Reflection/InterfaceProxyBuilder.cs +++ b/src/SMAPI/Framework/Reflection/InterfaceProxyBuilder.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Reflection.Emit; +using System.Runtime.CompilerServices; namespace StardewModdingAPI.Framework.Reflection { @@ -14,7 +15,7 @@ namespace StardewModdingAPI.Framework.Reflection *********/ private static readonly string TargetFieldName = "__Target"; private static readonly string GlueFieldName = "__Glue"; - private static readonly MethodInfo CreateInstanceForProxyTypeNameMethod = typeof(InterfaceProxyGlue).GetMethod(nameof(InterfaceProxyGlue.CreateInstanceForProxyTypeName), new Type[] { typeof(string), typeof(object) }); + private static readonly MethodInfo ObtainInstanceForProxyTypeNameMethod = typeof(InterfaceProxyGlue).GetMethod(nameof(InterfaceProxyGlue.ObtainInstanceForProxyTypeName), new Type[] { typeof(string), typeof(object) }); /********* ** Fields @@ -28,6 +29,8 @@ namespace StardewModdingAPI.Framework.Reflection /// <summary>The generated proxy type.</summary> private Type ProxyType; + /// <summary>A cache of all proxies generated by this builder.</summary> + private readonly ConditionalWeakTable<object, object> ProxyCache = new(); /********* ** Public methods @@ -168,15 +171,20 @@ namespace StardewModdingAPI.Framework.Reflection this.ProxyType = proxyBuilder.CreateType(); } - /// <summary>Create an instance of the proxy for a target instance.</summary> + /// <summary>Get an existing or create a new instance of the proxy for a target instance.</summary> /// <param name="targetInstance">The target instance.</param> /// <param name="factory">The <see cref="InterfaceProxyFactory"/> that requested to build a proxy.</param> - public object CreateInstance(object targetInstance, InterfaceProxyFactory factory) + public object ObtainInstance(object targetInstance, InterfaceProxyFactory factory) { + if (this.ProxyCache.TryGetValue(targetInstance, out object proxyInstance)) + return proxyInstance; + ConstructorInfo constructor = this.ProxyType.GetConstructor(new[] { this.TargetType, typeof(InterfaceProxyGlue) }); if (constructor == null) throw new InvalidOperationException($"Couldn't find the constructor for generated proxy type '{this.ProxyType.Name}'."); // should never happen - return constructor.Invoke(new[] { targetInstance, new InterfaceProxyGlue(factory) }); + proxyInstance = constructor.Invoke(new[] { targetInstance, new InterfaceProxyGlue(factory) }); + this.ProxyCache.Add(targetInstance, proxyInstance); + return proxyInstance; } @@ -297,7 +305,7 @@ namespace StardewModdingAPI.Framework.Reflection il.Emit(OpCodes.Ldfld, glueField); il.Emit(OpCodes.Ldstr, proxyTypeName); il.Emit(OpCodes.Ldloc, inputLocal); - il.Emit(OpCodes.Call, CreateInstanceForProxyTypeNameMethod); + il.Emit(OpCodes.Call, ObtainInstanceForProxyTypeNameMethod); il.Emit(OpCodes.Castclass, outputLocal.LocalType); il.Emit(OpCodes.Stloc, outputLocal); diff --git a/src/SMAPI/Framework/Reflection/InterfaceProxyFactory.cs b/src/SMAPI/Framework/Reflection/InterfaceProxyFactory.cs index 72b4254c..daeac2ad 100644 --- a/src/SMAPI/Framework/Reflection/InterfaceProxyFactory.cs +++ b/src/SMAPI/Framework/Reflection/InterfaceProxyFactory.cs @@ -42,7 +42,7 @@ namespace StardewModdingAPI.Framework.Reflection // create instance InterfaceProxyBuilder builder = this.ObtainBuilder(instance.GetType(), typeof(TInterface), sourceModID, targetModID); - return (TInterface)builder.CreateInstance(instance, this); + return (TInterface)builder.ObtainInstance(instance, this); } internal InterfaceProxyBuilder ObtainBuilder(Type targetType, Type interfaceType, string sourceModID, string targetModID) diff --git a/src/SMAPI/Framework/Reflection/InterfaceProxyGlue.cs b/src/SMAPI/Framework/Reflection/InterfaceProxyGlue.cs index 8d0d74a7..f98b54a2 100644 --- a/src/SMAPI/Framework/Reflection/InterfaceProxyGlue.cs +++ b/src/SMAPI/Framework/Reflection/InterfaceProxyGlue.cs @@ -10,13 +10,13 @@ namespace StardewModdingAPI.Framework.Reflection this.Factory = factory; } - /// <summary>Creates a new proxied instance by its type name.</summary> + /// <summary>Get an existing or create a new proxied instance by its type name.</summary> /// <param name="proxyTypeName">The full name of the proxy type.</param> /// <param name="toProxy">The target instance to proxy.</param> - public object CreateInstanceForProxyTypeName(string proxyTypeName, object toProxy) + public object ObtainInstanceForProxyTypeName(string proxyTypeName, object toProxy) { var builder = this.Factory.GetBuilderByProxyTypeName(proxyTypeName); - return builder.CreateInstance(toProxy, this.Factory); + return builder.ObtainInstance(toProxy, this.Factory); } } } |