diff --git a/Convention/[RScript] b/Convention/[RScript] index 29dd4f5..249a2f9 160000 --- a/Convention/[RScript] +++ b/Convention/[RScript] @@ -1 +1 @@ -Subproject commit 29dd4f5d96898b1cbca59c6f0d178591ebb8baa9 +Subproject commit 249a2f9ce36add06f13ca62b20a54ca23144398d diff --git a/Convention/[Runtime]/Config.cs b/Convention/[Runtime]/Config.cs index 7189a84..d358e72 100644 --- a/Convention/[Runtime]/Config.cs +++ b/Convention/[Runtime]/Config.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Runtime.Serialization; +using System.Text; using System.Threading; using System.Xml; @@ -463,5 +464,362 @@ namespace Convention { return new EnumerableClass(ir); } + + /// + /// Marshal 相关的实用函数。 + /// + public static class Marshal + { + + [Serializable] + public class MarshalException : Exception + { + public MarshalException() { } + public MarshalException(string message) : base(message) { } + public MarshalException(string message, Exception inner) : base(message, inner) { } + } + + private const int BlockSize = 1024 * 4; + private static IntPtr s_CachedHGlobalPtr = IntPtr.Zero; + private static int s_CachedHGlobalSize = 0; + + /// + /// 获取缓存的从进程的非托管内存中分配的内存的大小。 + /// + public static int CachedHGlobalSize + { + get + { + return s_CachedHGlobalSize; + } + } + + /// + /// 确保从进程的非托管内存中分配足够大小的内存并缓存。 + /// + /// 要确保从进程的非托管内存中分配内存的大小。 + public static void EnsureCachedHGlobalSize(int ensureSize) + { + if (ensureSize < 0) + { + throw new MarshalException("Ensure size is invalid."); + } + + if (s_CachedHGlobalPtr == IntPtr.Zero || s_CachedHGlobalSize < ensureSize) + { + FreeCachedHGlobal(); + int size = (ensureSize - 1 + BlockSize) / BlockSize * BlockSize; + s_CachedHGlobalPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(size); + s_CachedHGlobalSize = size; + } + } + + /// + /// 释放缓存的从进程的非托管内存中分配的内存。 + /// + public static void FreeCachedHGlobal() + { + if (s_CachedHGlobalPtr != IntPtr.Zero) + { + System.Runtime.InteropServices.Marshal.FreeHGlobal(s_CachedHGlobalPtr); + s_CachedHGlobalPtr = IntPtr.Zero; + s_CachedHGlobalSize = 0; + } + } + + /// + /// 将数据从对象转换为二进制流。 + /// + /// 要转换的对象的类型。 + /// 要转换的对象。 + /// 存储转换结果的二进制流。 + public static byte[] StructureToBytes(T structure) + { + return StructureToBytes(structure, System.Runtime.InteropServices.Marshal.SizeOf(typeof(T))); + } + + /// + /// 将数据从对象转换为二进制流。 + /// + /// 要转换的对象的类型。 + /// 要转换的对象。 + /// 要转换的对象的大小。 + /// 存储转换结果的二进制流。 + internal static byte[] StructureToBytes(T structure, int structureSize) + { + if (structureSize < 0) + { + throw new MarshalException("Structure size is invalid."); + } + + EnsureCachedHGlobalSize(structureSize); + System.Runtime.InteropServices.Marshal.StructureToPtr(structure, s_CachedHGlobalPtr, true); + byte[] result = new byte[structureSize]; + System.Runtime.InteropServices.Marshal.Copy(s_CachedHGlobalPtr, result, 0, structureSize); + return result; + } + + /// + /// 将数据从对象转换为二进制流。 + /// + /// 要转换的对象的类型。 + /// 要转换的对象。 + /// 存储转换结果的二进制流。 + public static void StructureToBytes(T structure, byte[] result) + { + StructureToBytes(structure, System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)), result, 0); + } + + /// + /// 将数据从对象转换为二进制流。 + /// + /// 要转换的对象的类型。 + /// 要转换的对象。 + /// 要转换的对象的大小。 + /// 存储转换结果的二进制流。 + internal static void StructureToBytes(T structure, int structureSize, byte[] result) + { + StructureToBytes(structure, structureSize, result, 0); + } + + /// + /// 将数据从对象转换为二进制流。 + /// + /// 要转换的对象的类型。 + /// 要转换的对象。 + /// 存储转换结果的二进制流。 + /// 写入存储转换结果的二进制流的起始位置。 + public static void StructureToBytes(T structure, byte[] result, int startIndex) + { + StructureToBytes(structure, System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)), result, startIndex); + } + + /// + /// 将数据从对象转换为二进制流。 + /// + /// 要转换的对象的类型。 + /// 要转换的对象。 + /// 要转换的对象的大小。 + /// 存储转换结果的二进制流。 + /// 写入存储转换结果的二进制流的起始位置。 + internal static void StructureToBytes(T structure, int structureSize, byte[] result, int startIndex) + { + if (structureSize < 0) + { + throw new MarshalException("Structure size is invalid."); + } + + if (result == null) + { + throw new MarshalException("Result is invalid."); + } + + if (startIndex < 0) + { + throw new MarshalException("Start index is invalid."); + } + + if (startIndex + structureSize > result.Length) + { + throw new MarshalException("Result length is not enough."); + } + + EnsureCachedHGlobalSize(structureSize); + System.Runtime.InteropServices.Marshal.StructureToPtr(structure, s_CachedHGlobalPtr, true); + System.Runtime.InteropServices.Marshal.Copy(s_CachedHGlobalPtr, result, startIndex, structureSize); + } + + /// + /// 将数据从二进制流转换为对象。 + /// + /// 要转换的对象的类型。 + /// 要转换的二进制流。 + /// 存储转换结果的对象。 + public static T BytesToStructure(byte[] buffer) + { + return BytesToStructure(System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)), buffer, 0); + } + + /// + /// 将数据从二进制流转换为对象。 + /// + /// 要转换的对象的类型。 + /// 要转换的二进制流。 + /// 读取要转换的二进制流的起始位置。 + /// 存储转换结果的对象。 + public static T BytesToStructure(byte[] buffer, int startIndex) + { + return BytesToStructure(System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)), buffer, startIndex); + } + + /// + /// 将数据从二进制流转换为对象。 + /// + /// 要转换的对象的类型。 + /// 要转换的对象的大小。 + /// 要转换的二进制流。 + /// 存储转换结果的对象。 + internal static T BytesToStructure(int structureSize, byte[] buffer) + { + return BytesToStructure(structureSize, buffer, 0); + } + + /// + /// 将数据从二进制流转换为对象。 + /// + /// 要转换的对象的类型。 + /// 要转换的对象的大小。 + /// 要转换的二进制流。 + /// 读取要转换的二进制流的起始位置。 + /// 存储转换结果的对象。 + internal static T BytesToStructure(int structureSize, byte[] buffer, int startIndex) + { + if (structureSize < 0) + { + throw new MarshalException("Structure size is invalid."); + } + + if (buffer == null) + { + throw new MarshalException("Buffer is invalid."); + } + + if (startIndex < 0) + { + throw new MarshalException("Start index is invalid."); + } + + if (startIndex + structureSize > buffer.Length) + { + throw new MarshalException("Buffer length is not enough."); + } + + EnsureCachedHGlobalSize(structureSize); + System.Runtime.InteropServices.Marshal.Copy(buffer, startIndex, s_CachedHGlobalPtr, structureSize); + return (T)System.Runtime.InteropServices.Marshal.PtrToStructure(s_CachedHGlobalPtr, typeof(T)); + } + } + + /// + /// 获取类型的友好显示名称,支持泛型、数组等复杂类型 + /// + public static string GetFriendlyName(this Type type) + { + if (type == null) return null; + + // 处理泛型类型 + if (type.IsGenericType) + { + // 特殊处理可空类型(Nullable) + if (type.IsNullable()) + { + return $"{GetFriendlyName(type.GetGenericArguments()[0])}?"; + } + + var sb = new StringBuilder(); + // 获取类型基础名称(移除 `1, `2 等后缀) + string baseName = type.Name.Contains('`') ? type.Name[..type.Name.IndexOf('`')] : type.Name; + sb.Append(baseName); + sb.Append('<'); + + // 递归处理泛型参数 + Type[] args = type.GetGenericArguments(); + for (int i = 0; i < args.Length; i++) + { + if (i > 0) sb.Append(", "); + sb.Append(GetFriendlyName(args[i])); + } + + sb.Append('>'); + return sb.ToString(); + } + + // 处理数组类型 + if (type.IsArray) + { + string elementName = GetFriendlyName(type.GetElementType()); + int rank = type.GetArrayRank(); + return rank == 1 ? $"{elementName}[]" : $"{elementName}[{new string(',', rank - 1)}]"; + } + + // 处理指针类型 + if (type.IsPointer) + { + return $"{GetFriendlyName(type.GetElementType())}*"; + } + + // 处理引用类型(ref/out 参数) + if (type.IsByRef) + { + return $"{GetFriendlyName(type.GetElementType())}&"; + } + + // 普通类型直接返回名称 + return type.Name; + } + + /// + /// 判断是否为可空类型 + /// + public static bool IsNullable(this Type type) + { + return type.IsGenericType && + type.GetGenericTypeDefinition() == typeof(Nullable<>); + } } } + +namespace Convention +{ + public static partial class Utility + { + /// + /// 生成期望类型的栈实例 + /// + /// 期望类型 + /// + public static object CreateStack([In] Type type) + { + var stackType = typeof(Stack<>).MakeGenericType(type); + var stackInstance = Activator.CreateInstance(stackType); + return stackInstance; + } + + /// + /// 生成期望类型的队列实例 + /// + /// 期望类型 + /// + public static object CreateQueue([In] Type type) + { + var queueType = typeof(Queue<>).MakeGenericType(type); + var queueInstance = Activator.CreateInstance(queueType); + return queueInstance; + } + + /// + /// 生成期望类型的列表实例 + /// + /// 期望类型 + /// + public static object CreateList([In] Type type) + { + var listType = typeof(List<>).MakeGenericType(type); + var listInstance = Activator.CreateInstance(listType); + return listInstance; + } + + /// + /// 生成期望键值对类型的字典实例 + /// + /// 期望键类型 + /// 期望值类型 + /// + public static object CreateDictionary([In] Type keyType, [In] Type valueType) + { + var dictType = typeof(Dictionary<,>).MakeGenericType(keyType, valueType); + var dictInstance = Activator.CreateInstance(dictType); + return dictInstance; + } + } +} \ No newline at end of file diff --git a/[Test]/Program.cs b/[Test]/Program.cs index 5709dd1..584dbd6 100644 --- a/[Test]/Program.cs +++ b/[Test]/Program.cs @@ -6,34 +6,30 @@ using Convention.RScript.Variable.Attr; using Convention.RScript.Variable.CStyle; using System; using System.IO; +using System.Collections; +using System.Linq; +using System.Threading; public class Program { - [Description(@" -测试注释1 -测试注释二 -")] - [Default(@" -this.Log(1); -")] - public class Test + static int i = 0; + + static IEnumerator Test1() { - [Method] - public void Log(object o) - { - Console.WriteLine(o); - } + Console.WriteLine(i); + for(; ; ) + yield return null; + } + + static IEnumerator Test() + { + yield return Test1(); } static void Main(string[] args) { - var engine = new RScriptEngine(); - var testClass = new CScriptRScriptVariableGenerater(typeof(Test), () => new Test(), null, nameof(Test)); - testClass.Register(); - engine.Run(@" -var t = New(Test); -t.Log(114514); -"); - Console.WriteLine(testClass.scriptIndicator); + var ir = Test(); + while (ir.MoveNext()) + Thread.Sleep(1000); } } \ No newline at end of file