using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Text; namespace Convention.RScript.Variable { namespace Attr { [AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)] public sealed class MethodAttribute : Attribute { } [AttributeUsage(AttributeTargets.Enum, Inherited = true, AllowMultiple = false)] public sealed class EnumAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class|AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] public sealed class DefaultAttribute : Attribute { public string defaultScript; public DefaultAttribute(string defaultScript) { this.defaultScript = defaultScript; } } } public abstract class RScriptInjectVariableGenerater { public string RScriptString { get; private set; } public abstract string GetFilename(Type currentType); 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); protected abstract string WriteEnumBodyExit(Type currentType); protected abstract string WriteEnumTail(Type currentType); #endregion #region Class protected abstract string WriteClassHead(Type currentType); protected abstract string WriteClassBodyEnter(Type currentType); protected abstract string WriteClassMethod(Type returnType, string methodName, string[] parameterNames, Type[] parameterTypes); protected abstract string WriteClassBodyExit(Type currentType); protected abstract string WriteClassTail(Type currentType); #endregion protected abstract string WritePageEnd(Type currentType); /// /// 生成targetType类型的实体 /// /// public delegate object Generater(); private Generater MyGenerater; public readonly static Dictionary AllRScriptInjectVariables = new(); public readonly Type targetType; public readonly string name; public readonly string scriptIndicator; public readonly string defaultScript; public object Generate() { return MyGenerater(); } public RScriptInjectVariableGenerater(Type targetType, [MaybeNull] Generater generater, string name) { if (AllRScriptInjectVariables.TryGetValue(name, out var exist_var)) { if (exist_var.MyGenerater != generater || exist_var.targetType != targetType) { throw new InvalidOperationException($"{name} is been used"); } this.targetType = exist_var.targetType; this.name = exist_var.name; this.scriptIndicator = exist_var.scriptIndicator; this.defaultScript = exist_var.defaultScript; } else { StringBuilder builder = new(); builder.AppendLine(this.WritePageHead(targetType)); builder.AppendLine(this.WriteClassHead(targetType)); builder.AppendLine(this.WriteClassBodyEnter(targetType)); // 绘制枚举 { var scriptEnums = from enumItem in targetType.GetNestedTypes(BindingFlags.NonPublic | BindingFlags.Public) where enumItem.GetCustomAttribute() != null select enumItem; foreach (var enumItem in scriptEnums) { var attr = enumItem.GetCustomAttribute(); this.WriteEnumHead(targetType); this.WriteEnumBodyEnter(targetType); foreach (var enumName in enumItem.GetEnumNames()) { this.WriteEnumName(enumName); } this.WriteEnumBodyExit(targetType); this.WriteEnumTail(targetType); } } // 绘制方法 { var scriptMethods = from method in targetType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly) where method.GetCustomAttribute() != null select method; foreach (var method in scriptMethods) { var attr = method.GetCustomAttribute(); 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)); builder.AppendLine(this.WritePageEnd(targetType)); this.scriptIndicator = builder.ToString(); } this.targetType = targetType; this.MyGenerater = generater; this.name = name; var defaultAttr = targetType.GetCustomAttribute(); this.defaultScript = defaultAttr?.defaultScript; } public static object GenerateRScriptVariable(string name) { if (AllRScriptInjectVariables.TryGetValue(name, out var variable)) { if (variable.MyGenerater != null) { var result = variable.Generate(); if (result.GetType().IsSubclassOf(variable.targetType) || result.GetType() == variable.targetType) return result; else throw new InvalidOperationException($"{name} target is not sub-class of it's target type"); } } throw new InvalidOperationException($"{name} target is not exist or abstract"); } } public static class RScriptVariableGenerater { public static object New(string name) { return RScriptInjectVariableGenerater.GenerateRScriptVariable(name); } } }