AyCode.Core/AyCode.Models.Server/DynamicMethods/AcDynamicMethodCallModel.cs

60 lines
2.4 KiB
C#

using System.Collections.Concurrent;
using System.Collections.Frozen;
using System.Reflection;
using AyCode.Services.SignalRs;
namespace AyCode.Models.Server.DynamicMethods;
public class AcDynamicMethodCallModel<TAttribute> where TAttribute : TagAttribute
{
/// <summary>
/// Statikus cache a típusok metódus metaadataihoz - a reflection csak egyszer fut le típusonként.
/// Key: Instance típus -> Value: immutable frozen dictionary a metódusokkal messageTag szerint
/// </summary>
private static readonly ConcurrentDictionary<Type, FrozenDictionary<int, AcMethodInfoModel<TAttribute>>> _typeMethodCache = new();
public object InstanceObject { get; init; }
/// <summary>
/// Immutable dictionary a metódusokkal messageTag szerint. Csak olvasásra használatos.
/// </summary>
public FrozenDictionary<int, AcMethodInfoModel<TAttribute>> MethodsByMessageTag { get; init; }
public AcDynamicMethodCallModel(Type instanceObjectType) : this(instanceObjectType, null!)
{
}
public AcDynamicMethodCallModel(Type instanceObjectType, params object[] constructorParams) : this(Activator.CreateInstance(instanceObjectType, constructorParams)!)
{
}
public AcDynamicMethodCallModel(object instanceObject)
{
InstanceObject = instanceObject;
MethodsByMessageTag = GetOrCreateMethodCache(instanceObject.GetType());
}
/// <summary>
/// Visszaadja a cache-elt metódus metaadatokat, vagy létrehozza őket ha még nincsenek.
/// A reflection csak egyszer fut le típusonként.
/// </summary>
private static FrozenDictionary<int, AcMethodInfoModel<TAttribute>> GetOrCreateMethodCache(Type instanceType)
{
return _typeMethodCache.GetOrAdd(instanceType, type =>
{
var methods = new Dictionary<int, AcMethodInfoModel<TAttribute>>();
foreach (var methodInfo in type.GetMethods())
{
if (methodInfo.GetCustomAttribute(typeof(TAttribute)) is not TAttribute attribute) continue;
if (methods.ContainsKey(attribute.MessageTag))
throw new Exception($"Multiple SignaRMessageTag! messageTag: {attribute.MessageTag}; methodName: {methodInfo.Name}");
methods[attribute.MessageTag] = new AcMethodInfoModel<TAttribute>(attribute, methodInfo!);
}
return methods.ToFrozenDictionary();
});
}
}