using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Text; using System.Threading; using System.Xml; namespace Convention { public static class PlatformIndicator { #if DEBUG public static bool IsRelease => false; #else public static bool IsRelease => true; #endif public static bool IsPlatformWindows => RuntimeInformation.IsOSPlatform(OSPlatform.Windows); public static bool IsPlatformLinux => RuntimeInformation.IsOSPlatform(OSPlatform.Linux); public static bool IsPlatformOsx => RuntimeInformation.IsOSPlatform(OSPlatform.OSX); public static bool IsPlatformX64 => System.Environment.Is64BitOperatingSystem; static PlatformIndicator() { MainThreadID = Thread.CurrentThread.ManagedThreadId; } public static int MainThreadID { get; private set; } public static bool CurrentThreadIsMainThread() { return MainThreadID == Thread.CurrentThread.ManagedThreadId; } public static string CompanyName = "DefaultCompany"; public static string ProductName = "DefaultProject"; public static string ApplicationPath => Environment.ProcessPath; public static string StreamingAssetsPath => Path.Combine(ApplicationPath, "StreamingAssets/"); public static string PersistentDataPath { get { if (IsPlatformWindows) return Environment.ExpandEnvironmentVariables($@"%userprofile%\AppData\LocalLow\{CompanyName}\{ProductName}\"); else if (IsPlatformLinux) return Environment.ExpandEnvironmentVariables(@"$HOME/.config/"); return ""; } } public static string DataPath => "Assets/"; } public static partial class Utility { //[MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ConvertString(object obj) { return Convert.ToString(obj); } public static T ConvertValue(string str) { Type type = typeof(T); var parse_method = type.GetMethod("Parse", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(string) }, null); if (parse_method != null && (parse_method.ReturnType.IsSubclassOf(type) || parse_method.ReturnType == type) && parse_method.GetParameters().Length == 1 && parse_method.GetParameters()[0].ParameterType == typeof(string)) { return (T)parse_method.Invoke(null, new object[] { str }); } throw new InvalidCastException($"\"{str}\" is cannt convert to type<{type}>"); } /// /// 序列化 /// /// /// public static byte[] Serialize(T obj) { ArgumentNullException.ThrowIfNull(obj); using var memoryStream = new MemoryStream(); DataContractSerializer ser = new DataContractSerializer(typeof(T)); ser.WriteObject(memoryStream, obj); var data = memoryStream.ToArray(); return data; } /// /// 反序列化 /// /// /// /// public static T Deserialize(byte[] data) { ArgumentNullException.ThrowIfNull(data); using var memoryStream = new MemoryStream(data); XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(memoryStream, new XmlDictionaryReaderQuotas()); DataContractSerializer ser = new DataContractSerializer(typeof(T)); var result = (T)ser.ReadObject(reader, true); return result; } public static object SeekValue(object obj, string name, BindingFlags flags, out bool isSucceed) { Type type = obj.GetType(); var field = type.GetField(name, flags); isSucceed = true; if (field != null) { return field.GetValue(obj); } var property = type.GetProperty(name, flags); if (property != null) { return property.GetValue(obj); } isSucceed = false; return null; } public static object SeekValue(object obj, string name, BindingFlags flags) { Type type = obj.GetType(); var field = type.GetField(name, flags); if (field != null) { return field.GetValue(obj); } var property = type.GetProperty(name, flags); if (property != null) { return property.GetValue(obj); } return null; } public static object SeekValue(object obj, string name, Type valueType, BindingFlags flags, out bool isSucceed) { Type type = obj.GetType(); var field = type.GetField(name, flags); isSucceed = true; if (field != null && field.FieldType == valueType) { return field.GetValue(obj); } var property = type.GetProperty(name, flags); if (property != null && property.PropertyType == valueType) { return property.GetValue(obj); } isSucceed = false; return null; } public static object SeekValue(object obj, string name, Type valueType, BindingFlags flags) { Type type = obj.GetType(); var field = type.GetField(name, flags); if (field != null && field.FieldType == valueType) { return field.GetValue(obj); } var property = type.GetProperty(name, flags); if (property != null && property.PropertyType == valueType) { return property.GetValue(obj); } return null; } public static bool PushValue(object obj, object value, string name, BindingFlags flags) { Type type = obj.GetType(); var field = type.GetField(name, flags); if (field != null) { field.SetValue(obj, value); return true; } var property = type.GetProperty(name, flags); if (property != null) { property.SetValue(obj, value); return true; } return false; } public static List SeekType(Predicate pr, IEnumerable assemblys = null, int findCount = -1) { List types = new List(); if (assemblys == null) assemblys = AppDomain.CurrentDomain.GetAssemblies(); foreach (var assembly in assemblys) { foreach (var type in assembly.GetTypes()) { if (pr(type)) types.Add(type); if (types.Count == findCount) return types; } } return types; } public static List GetMemberInfos(Type type, IEnumerable cutOffType = null, bool isGetNotPublic = false, bool isGetStatic = false) { Type current = type; BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly; List result = new(); if (isGetNotPublic) flags |= BindingFlags.NonPublic; if (isGetStatic) flags |= BindingFlags.Static; while ((cutOffType != null && !cutOffType.Contains(current)) && current != null) { result.AddRange(current.GetFields(flags)); result.AddRange(current.GetProperties(flags)); result.AddRange(current.GetMethods(flags)); current = current.BaseType; } return result; } public static bool IsNumber([In] object data) { if (data == null) return false; var type = data.GetType(); return IsNumber(type); } public static bool IsString([In] object data) { if (data == null) return false; var type = data.GetType(); return IsString(type); } public static bool IsBinary([In] object data) { if (data == null) return false; var type = data.GetType(); return IsBinary(type); } public static bool IsArray([In] object data) { if (data == null) return false; var type = data.GetType(); return IsArray(type); } public static bool IsBool([In] object data) { if (data == null) return false; return IsBool(data.GetType()); } public static bool IsNumber([In] Type type) { return type == typeof(double) || type == typeof(float) || type == typeof(int) || type == typeof(long) || type == typeof(sbyte) || type == typeof(short) || type == typeof(ushort) || type == typeof(uint) || type == typeof(ulong) || type == typeof(char); } public static bool IsString([In] Type type) { return type == typeof(string) || type == typeof(char[]); } public static bool IsBinary([In] Type type) { return type == typeof(byte) || type == typeof(sbyte) || type == typeof(byte[]) || type == typeof(sbyte[]); } public static bool IsArray([In] Type type) { return type.IsArray; } public static bool IsBool([In] Type type) { return type == typeof(bool); } public static bool IsEnum([In] Type type) { return type.IsEnum; } public static bool HasCustomAttribute(MemberInfo member, IEnumerable attrs) { foreach (var attr in attrs) { if (member.GetCustomAttribute(attr, true) != null) return true; } return false; } public static Type GetMemberValueType(MemberInfo member) { if (member is FieldInfo field) { return field.FieldType; } else if (member is PropertyInfo property) { return property.PropertyType; } return null; } public static bool GetMemberValueType(MemberInfo member, out Type type) { if (member is FieldInfo field) { type = field.FieldType; return true; } else if (member is PropertyInfo property) { type = property.PropertyType; return true; } type = null; return false; } public static void PushValue(object target, object value, MemberInfo info) { if (info is FieldInfo field) { if (value.GetType().IsSubclassOf(field.FieldType)) field.SetValue(target, value); else { field.SetValue(target, field.FieldType.GetMethod(nameof(float.Parse)).Invoke(target, new object[] { value })); } } else if (info is PropertyInfo property) { property.SetValue(target, value); } else { throw new InvalidOperationException("info is unsupport"); } } public static object SeekValue(object target, MemberInfo info) { if (info is FieldInfo field) { return field.GetValue(target); } else if (info is PropertyInfo property) { return property.GetValue(target); } else { throw new InvalidOperationException("info is unsupport"); } } public static bool TrySeekValue(object target, MemberInfo info, out object value) { if (info is FieldInfo field) { value = field.GetValue(target); return true; } else if (info is PropertyInfo property) { value = property.GetValue(target); return true; } value = null; return false; } public static List SeekMemberInfo(object target, IEnumerable attrs, IEnumerable types, Type untilBase = null) { Type _CurType = target.GetType(); List result = new(); result.AddRange(_CurType.GetMembers(BindingFlags.Public | BindingFlags.Instance)); while (_CurType != null && _CurType != typeof(object) && _CurType != untilBase) { result.AddRange( from info in _CurType.GetMembers(BindingFlags.NonPublic | BindingFlags.Instance) where attrs == null || HasCustomAttribute(info, attrs) where types == null || (GetMemberValueType(info, out var type) && types.Contains(type)) select info ); _CurType = _CurType.BaseType; } return result; } public static List SeekMemberInfo(object target, IEnumerable names, BindingFlags flags = BindingFlags.Default) { Type _CurType = target.GetType(); List result = _CurType.GetMembers(flags).ToList(); HashSet nameSet = names.ToHashSet(); result.RemoveAll(x => nameSet.Contains(x.Name) == false); return result; } public static object InvokeMember(MemberInfo member, object target, params object[] parameters) { if (member is MethodInfo method) { return method.Invoke(target, parameters); } return null; } public static bool TryInvokeMember(MemberInfo member, object target, out object returnValue, params object[] parameters) { returnValue = null; if (member is MethodInfo method) { returnValue = method.Invoke(target, parameters); return true; } else return false; } public static T Shared(T target, out T value) { value = target; return value; } public static string NowFormat(string format = "yyyy-MM-dd_HH-mm-ss") { return DateTime.Now.ToString(format); } public class EnumerableClass : IEnumerable { private readonly IEnumerator ir; public EnumerableClass(IEnumerator ir) { this.ir = ir; } public IEnumerator GetEnumerator() { return ir; } } public static IEnumerable AsEnumerable(this IEnumerator ir) { 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; } } }