825 lines
30 KiB
C#
825 lines
30 KiB
C#
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<T>(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}>");
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 序列化
|
||
/// </summary>
|
||
/// <param name="obj"></param>
|
||
/// <returns></returns>
|
||
public static byte[] Serialize<T>(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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 反序列化
|
||
/// </summary>
|
||
/// <typeparam name="T"></typeparam>
|
||
/// <param name="data"></param>
|
||
/// <returns></returns>
|
||
public static T Deserialize<T>(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<Type> SeekType(Predicate<Type> pr, IEnumerable<Assembly> assemblys = null, int findCount = -1)
|
||
{
|
||
List<Type> types = new List<Type>();
|
||
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<MemberInfo> GetMemberInfos(Type type, IEnumerable<Type> cutOffType = null, bool isGetNotPublic = false, bool isGetStatic = false)
|
||
{
|
||
Type current = type;
|
||
BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;
|
||
List<MemberInfo> 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<Type> 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<MemberInfo> SeekMemberInfo(object target, IEnumerable<Type> attrs, IEnumerable<Type> types, Type untilBase = null)
|
||
{
|
||
Type _CurType = target.GetType();
|
||
List<MemberInfo> 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<MemberInfo> SeekMemberInfo(object target, IEnumerable<string> names, BindingFlags flags = BindingFlags.Default)
|
||
{
|
||
Type _CurType = target.GetType();
|
||
List<MemberInfo> result = _CurType.GetMembers(flags).ToList();
|
||
HashSet<string> 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>(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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Marshal 相关的实用函数。
|
||
/// </summary>
|
||
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;
|
||
|
||
/// <summary>
|
||
/// 获取缓存的从进程的非托管内存中分配的内存的大小。
|
||
/// </summary>
|
||
public static int CachedHGlobalSize
|
||
{
|
||
get
|
||
{
|
||
return s_CachedHGlobalSize;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 确保从进程的非托管内存中分配足够大小的内存并缓存。
|
||
/// </summary>
|
||
/// <param name="ensureSize">要确保从进程的非托管内存中分配内存的大小。</param>
|
||
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;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 释放缓存的从进程的非托管内存中分配的内存。
|
||
/// </summary>
|
||
public static void FreeCachedHGlobal()
|
||
{
|
||
if (s_CachedHGlobalPtr != IntPtr.Zero)
|
||
{
|
||
System.Runtime.InteropServices.Marshal.FreeHGlobal(s_CachedHGlobalPtr);
|
||
s_CachedHGlobalPtr = IntPtr.Zero;
|
||
s_CachedHGlobalSize = 0;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将数据从对象转换为二进制流。
|
||
/// </summary>
|
||
/// <typeparam name="T">要转换的对象的类型。</typeparam>
|
||
/// <param name="structure">要转换的对象。</param>
|
||
/// <returns>存储转换结果的二进制流。</returns>
|
||
public static byte[] StructureToBytes<T>(T structure)
|
||
{
|
||
return StructureToBytes(structure, System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将数据从对象转换为二进制流。
|
||
/// </summary>
|
||
/// <typeparam name="T">要转换的对象的类型。</typeparam>
|
||
/// <param name="structure">要转换的对象。</param>
|
||
/// <param name="structureSize">要转换的对象的大小。</param>
|
||
/// <returns>存储转换结果的二进制流。</returns>
|
||
internal static byte[] StructureToBytes<T>(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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将数据从对象转换为二进制流。
|
||
/// </summary>
|
||
/// <typeparam name="T">要转换的对象的类型。</typeparam>
|
||
/// <param name="structure">要转换的对象。</param>
|
||
/// <param name="result">存储转换结果的二进制流。</param>
|
||
public static void StructureToBytes<T>(T structure, byte[] result)
|
||
{
|
||
StructureToBytes(structure, System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)), result, 0);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将数据从对象转换为二进制流。
|
||
/// </summary>
|
||
/// <typeparam name="T">要转换的对象的类型。</typeparam>
|
||
/// <param name="structure">要转换的对象。</param>
|
||
/// <param name="structureSize">要转换的对象的大小。</param>
|
||
/// <param name="result">存储转换结果的二进制流。</param>
|
||
internal static void StructureToBytes<T>(T structure, int structureSize, byte[] result)
|
||
{
|
||
StructureToBytes(structure, structureSize, result, 0);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将数据从对象转换为二进制流。
|
||
/// </summary>
|
||
/// <typeparam name="T">要转换的对象的类型。</typeparam>
|
||
/// <param name="structure">要转换的对象。</param>
|
||
/// <param name="result">存储转换结果的二进制流。</param>
|
||
/// <param name="startIndex">写入存储转换结果的二进制流的起始位置。</param>
|
||
public static void StructureToBytes<T>(T structure, byte[] result, int startIndex)
|
||
{
|
||
StructureToBytes(structure, System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)), result, startIndex);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将数据从对象转换为二进制流。
|
||
/// </summary>
|
||
/// <typeparam name="T">要转换的对象的类型。</typeparam>
|
||
/// <param name="structure">要转换的对象。</param>
|
||
/// <param name="structureSize">要转换的对象的大小。</param>
|
||
/// <param name="result">存储转换结果的二进制流。</param>
|
||
/// <param name="startIndex">写入存储转换结果的二进制流的起始位置。</param>
|
||
internal static void StructureToBytes<T>(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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将数据从二进制流转换为对象。
|
||
/// </summary>
|
||
/// <typeparam name="T">要转换的对象的类型。</typeparam>
|
||
/// <param name="buffer">要转换的二进制流。</param>
|
||
/// <returns>存储转换结果的对象。</returns>
|
||
public static T BytesToStructure<T>(byte[] buffer)
|
||
{
|
||
return BytesToStructure<T>(System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)), buffer, 0);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将数据从二进制流转换为对象。
|
||
/// </summary>
|
||
/// <typeparam name="T">要转换的对象的类型。</typeparam>
|
||
/// <param name="buffer">要转换的二进制流。</param>
|
||
/// <param name="startIndex">读取要转换的二进制流的起始位置。</param>
|
||
/// <returns>存储转换结果的对象。</returns>
|
||
public static T BytesToStructure<T>(byte[] buffer, int startIndex)
|
||
{
|
||
return BytesToStructure<T>(System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)), buffer, startIndex);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将数据从二进制流转换为对象。
|
||
/// </summary>
|
||
/// <typeparam name="T">要转换的对象的类型。</typeparam>
|
||
/// <param name="structureSize">要转换的对象的大小。</param>
|
||
/// <param name="buffer">要转换的二进制流。</param>
|
||
/// <returns>存储转换结果的对象。</returns>
|
||
internal static T BytesToStructure<T>(int structureSize, byte[] buffer)
|
||
{
|
||
return BytesToStructure<T>(structureSize, buffer, 0);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将数据从二进制流转换为对象。
|
||
/// </summary>
|
||
/// <typeparam name="T">要转换的对象的类型。</typeparam>
|
||
/// <param name="structureSize">要转换的对象的大小。</param>
|
||
/// <param name="buffer">要转换的二进制流。</param>
|
||
/// <param name="startIndex">读取要转换的二进制流的起始位置。</param>
|
||
/// <returns>存储转换结果的对象。</returns>
|
||
internal static T BytesToStructure<T>(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));
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取类型的友好显示名称,支持泛型、数组等复杂类型
|
||
/// </summary>
|
||
public static string GetFriendlyName(this Type type)
|
||
{
|
||
if (type == null) return null;
|
||
|
||
// 处理泛型类型
|
||
if (type.IsGenericType)
|
||
{
|
||
// 特殊处理可空类型(Nullable<T>)
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 判断是否为可空类型
|
||
/// </summary>
|
||
public static bool IsNullable(this Type type)
|
||
{
|
||
return type.IsGenericType &&
|
||
type.GetGenericTypeDefinition() == typeof(Nullable<>);
|
||
}
|
||
}
|
||
}
|
||
|
||
namespace Convention
|
||
{
|
||
public static partial class Utility
|
||
{
|
||
/// <summary>
|
||
/// 生成期望类型的栈实例
|
||
/// </summary>
|
||
/// <param name="type">期望类型</param>
|
||
/// <returns></returns>
|
||
public static object CreateStack([In] Type type)
|
||
{
|
||
var stackType = typeof(Stack<>).MakeGenericType(type);
|
||
var stackInstance = Activator.CreateInstance(stackType);
|
||
return stackInstance;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成期望类型的队列实例
|
||
/// </summary>
|
||
/// <param name="type">期望类型</param>
|
||
/// <returns></returns>
|
||
public static object CreateQueue([In] Type type)
|
||
{
|
||
var queueType = typeof(Queue<>).MakeGenericType(type);
|
||
var queueInstance = Activator.CreateInstance(queueType);
|
||
return queueInstance;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成期望类型的列表实例
|
||
/// </summary>
|
||
/// <param name="type">期望类型</param>
|
||
/// <returns></returns>
|
||
public static object CreateList([In] Type type)
|
||
{
|
||
var listType = typeof(List<>).MakeGenericType(type);
|
||
var listInstance = Activator.CreateInstance(listType);
|
||
return listInstance;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成期望键值对类型的字典实例
|
||
/// </summary>
|
||
/// <param name="keyType">期望键类型</param>
|
||
/// <param name="valueType">期望值类型</param>
|
||
/// <returns></returns>
|
||
public static object CreateDictionary([In] Type keyType, [In] Type valueType)
|
||
{
|
||
var dictType = typeof(Dictionary<,>).MakeGenericType(keyType, valueType);
|
||
var dictInstance = Activator.CreateInstance(dictType);
|
||
return dictInstance;
|
||
}
|
||
}
|
||
} |