summaryrefslogtreecommitdiff
path: root/src/SMAPI/Framework/Reflection
diff options
context:
space:
mode:
authorShockah <me@shockah.pl>2022-02-10 11:43:35 +0100
committerShockah <me@shockah.pl>2022-02-10 11:43:35 +0100
commit07259452170a253c44d5c2be68fc2342a88d2504 (patch)
treebb8b4c634db71f5b1f5c7e14539c58954aed9356 /src/SMAPI/Framework/Reflection
parent61415e41eb8f5f61e8b241255162257191c0a766 (diff)
downloadSMAPI-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.cs18
-rw-r--r--src/SMAPI/Framework/Reflection/InterfaceProxyFactory.cs2
-rw-r--r--src/SMAPI/Framework/Reflection/InterfaceProxyGlue.cs6
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);
}
}
}