Files
RScript/PublicTypes/RScriptInjectVariableGenerater.cs

274 lines
10 KiB
C#
Raw Normal View History

using Flee.InternalTypes;
using System;
2025-10-21 15:31:28 +08:00
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Text;
namespace Convention.RScript.Variable
{
2025-10-25 16:08:12 +08:00
namespace Attr
2025-10-21 15:31:28 +08:00
{
2025-10-25 16:08:12 +08:00
[AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public sealed class MethodAttribute : Attribute
2025-10-25 16:08:12 +08:00
{
}
[AttributeUsage(AttributeTargets.Enum, Inherited = true, AllowMultiple = false)]
public sealed class EnumAttribute : Attribute
2025-10-25 16:08:12 +08:00
{
}
2025-10-27 00:29:32 +08:00
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Struct, Inherited = false, AllowMultiple = false)]
public sealed class DefaultAttribute : Attribute
{
public string defaultScript;
public DefaultAttribute(string defaultScript)
{
this.defaultScript = defaultScript;
}
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false, AllowMultiple = false)]
public sealed class DescriptionAttribute : Attribute
{
public string description;
public DescriptionAttribute(string description)
{
this.description = description;
}
}
2025-10-21 15:31:28 +08:00
}
2025-10-27 00:29:32 +08:00
public abstract class RScriptInjectVariableGenerater
2025-10-21 15:31:28 +08:00
{
public string RScriptString { get; private set; }
public abstract string GetFilename(Type currentType);
2025-10-25 16:08:12 +08:00
protected abstract string WritePageHead(Type currentType);
#region Enum
protected abstract string WriteEnumHead(Type currentEnum);
protected abstract string WriteEnumBodyEnter(Type currentType);
protected abstract string WriteEnumName(string enumName);
2025-10-25 16:08:12 +08:00
protected abstract string WriteEnumBodyExit(Type currentType);
protected abstract string WriteEnumTail(Type currentType);
#endregion
#region Class
2025-10-21 15:31:28 +08:00
protected abstract string WriteClassHead(Type currentType);
protected abstract string WriteClassBodyEnter(Type currentType);
protected abstract string WriteClassMethod(Type returnType, string methodName, string[] parameterNames, Type[] parameterTypes);
2025-10-21 15:31:28 +08:00
protected abstract string WriteClassBodyExit(Type currentType);
protected abstract string WriteClassTail(Type currentType);
2025-10-25 16:08:12 +08:00
#endregion
protected abstract string WritePageEnd(Type currentType);
/// <summary>
/// 生成targetType类型的实体
/// </summary>
/// <returns></returns>
2025-10-21 15:31:28 +08:00
public delegate object Generater();
public delegate void Destorier(object o);
private readonly Generater MyGenerater;
private readonly Destorier MyDestorier;
private readonly HashSet<object> GenerateObjects = new();
2025-10-25 16:08:12 +08:00
2025-10-27 00:29:32 +08:00
public readonly static Dictionary<string, RScriptInjectVariableGenerater> AllRScriptInjectVariables = new();
2025-10-25 16:08:12 +08:00
public readonly Type targetType;
2025-10-25 16:08:12 +08:00
public readonly string name;
2025-10-27 00:29:32 +08:00
public readonly string scriptIndicator;
public readonly string defaultScript;
public readonly string description;
2025-10-25 16:08:12 +08:00
2025-10-21 15:31:28 +08:00
public object Generate()
{
return MyGenerater();
}
public RScriptInjectVariableGenerater(Type targetType, [MaybeNull] Generater generater, [MaybeNull] Destorier destorier, string name)
2025-10-21 15:31:28 +08:00
{
if (AllRScriptInjectVariables.TryGetValue(name, out var exist_var))
{
throw new InvalidOperationException($"{name} is been used");
}
this.targetType = targetType;
this.MyGenerater = generater;
this.MyDestorier = destorier;
this.name = name;
var defaultAttr = targetType.GetCustomAttribute<Attr.DefaultAttribute>();
this.defaultScript = defaultAttr?.defaultScript ?? "";
var descriptionAttr = targetType.GetCustomAttribute<Attr.DescriptionAttribute>();
this.description = descriptionAttr?.description ?? "";
StringBuilder builder = new();
builder.AppendLine(this.WritePageHead(targetType));
2025-11-25 17:03:43 +08:00
if (targetType.IsEnum)
2025-10-21 15:31:28 +08:00
{
2025-11-25 17:03:43 +08:00
// 绘制枚举
builder.AppendLine(this.WriteEnumHead(targetType));
builder.AppendLine(this.WriteEnumBodyEnter(targetType));
foreach (var enumName in targetType.GetEnumNames())
2025-10-25 16:08:12 +08:00
{
2025-11-25 17:03:43 +08:00
builder.AppendLine(this.WriteEnumName(enumName));
2025-10-25 16:08:12 +08:00
}
2025-11-25 17:03:43 +08:00
builder.AppendLine(this.WriteEnumBodyExit(targetType));
builder.AppendLine(this.WriteEnumTail(targetType));
}
2025-11-25 17:03:43 +08:00
else
{
2025-11-25 17:03:43 +08:00
builder.AppendLine(this.WriteClassHead(targetType));
builder.AppendLine(this.WriteClassBodyEnter(targetType));
// 绘制枚举
2025-10-25 16:08:12 +08:00
{
2025-11-25 17:03:43 +08:00
var scriptEnums = from enumItem in targetType.GetNestedTypes(BindingFlags.NonPublic | BindingFlags.Public)
where enumItem.GetCustomAttribute<Attr.EnumAttribute>() != null
select enumItem;
foreach (var enumItem in scriptEnums)
{
var attr = enumItem.GetCustomAttribute<Attr.EnumAttribute>();
this.WriteEnumHead(targetType);
this.WriteEnumBodyEnter(targetType);
foreach (var enumName in enumItem.GetEnumNames())
{
this.WriteEnumName(enumName);
}
this.WriteEnumBodyExit(targetType);
this.WriteEnumTail(targetType);
}
2025-10-25 16:08:12 +08:00
}
2025-11-25 17:03:43 +08:00
// 绘制方法
{
var scriptMethods = from method in targetType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly)
where method.GetCustomAttribute<Attr.MethodAttribute>() != null
select method;
foreach (var method in scriptMethods)
{
var attr = method.GetCustomAttribute<Attr.MethodAttribute>();
var returnType = method.ReturnType;
var methodName = method.Name;
var parameters = method.GetParameters();
var parameterNames = from item in parameters select item.Name;
var parameterTypes = from item in parameters select item.ParameterType;
builder.AppendLine(this.WriteClassMethod(returnType, methodName, parameterNames.ToArray(), parameterTypes.ToArray()));
}
}
builder.AppendLine(this.WriteClassBodyExit(targetType));
builder.AppendLine(this.WriteClassTail(targetType));
2025-10-21 15:31:28 +08:00
}
builder.AppendLine(this.WritePageEnd(targetType));
this.scriptIndicator = builder.ToString();
}
2025-10-21 15:31:28 +08:00
public void Register()
{
AllRScriptInjectVariables.Add(name, this);
}
public bool Unregister()
{
if (MyDestorier != null)
foreach (var item in GenerateObjects)
{
MyDestorier(item);
}
this.GenerateObjects.Clear();
return AllRScriptInjectVariables.Remove(name);
2025-10-21 15:31:28 +08:00
}
2025-11-25 17:03:43 +08:00
public class EnumGetter
{
public Type enumType;
public EnumGetter(Type enumType)
{
this.enumType = enumType;
}
public object Get(string name)
{
return Enum.Parse(enumType, name);
}
}
public static object GenerateRScriptVariable(string name)
2025-10-21 15:31:28 +08:00
{
if (AllRScriptInjectVariables.TryGetValue(name, out var variable))
2025-10-21 15:31:28 +08:00
{
2025-11-25 17:03:43 +08:00
if (variable.targetType.IsEnum)
{
2025-11-25 17:03:43 +08:00
if (variable.MyGenerater != null)
{
2025-11-25 17:03:43 +08:00
var result = variable.Generate();
if (result.GetType().IsSubclassOf(variable.targetType) || result.GetType() == variable.targetType)
{
variable.GenerateObjects.Add(result);
return result;
}
else
throw new InvalidOperationException($"{name} target is not sub-class of it's target type");
}
else
2025-11-25 17:03:43 +08:00
{
return variable.targetType;
}
}
else
{
if (variable.MyGenerater != null)
{
var result = variable.Generate();
if (result.GetType().IsSubclassOf(variable.targetType) || result.GetType() == variable.targetType)
{
variable.GenerateObjects.Add(result);
return result;
}
else
throw new InvalidOperationException($"{name} target is not sub-class of it's target type");
}
}
2025-10-21 15:31:28 +08:00
}
throw new InvalidOperationException($"{name} target is not exist or abstract");
}
public static string DestoryRScriptVariable(object o)
{
if (o == null)
return string.Empty;
foreach (var (name,variable) in AllRScriptInjectVariables)
{
variable.GenerateObjects.RemoveWhere(x => x == null);
if(variable.GenerateObjects.Remove(o))
{
variable.MyDestorier(o);
return variable.name;
}
}
return string.Empty;
}
2025-10-21 15:31:28 +08:00
}
public static class RScriptVariableGenerater
{
public static object New(string name)
{
2025-10-27 00:29:32 +08:00
return RScriptInjectVariableGenerater.GenerateRScriptVariable(name);
}
public static string Delete(object o)
{
return RScriptInjectVariableGenerater.DestoryRScriptVariable(o);
}
}
2025-10-21 15:31:28 +08:00
}