60 lines
2.4 KiB
C#
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();
|
|
});
|
|
}
|
|
} |