BS 0.1.0 开始构建Config内容

This commit is contained in:
2025-07-09 00:01:38 +08:00
parent 6a9687a934
commit 776a4d9152
16 changed files with 1394 additions and 0 deletions

View File

@@ -0,0 +1,107 @@
[返回](./Runtime-README.md)
# /Convention/Runtime/Architecture
---
核心架构模块,提供依赖注入、事件系统和时间线管理功能
## 接口定义
系统定义了以下核心接口来规范架构设计:
### ISignal
信号接口,用于事件系统的消息传递
### IModel
模型接口,定义数据模型的序列化和反序列化能力:
- `Save()` 保存数据到字符串
- `Load(string data)` 从字符串加载数据
### IConvertable<T>
转换接口,提供类型转换能力:
- `ConvertTo()` 转换为目标类型
### IConvertModel<T>
组合接口,同时继承 `IModel``IConvertable<T>`
## 核心类型
### SingletonModel<T>
泛型单例模型,提供类型安全的单例管理:
- 支持依赖注入和实例替换
- 提供隐式转换操作符
- 集成模型序列化功能
### DependenceModel
依赖模型,管理多个条件的组合验证:
- 支持多个 `IConvertModel<bool>` 的依赖关系
- 提供枚举接口遍历所有依赖
- 所有依赖条件均满足时返回true
## 注册系统
### 对象注册
- `Register(Type slot, object target, Action completer, params Type[] dependences)`
- `Register<T>(T target, Action completer, params Type[] dependences)`
提供基于类型的依赖注入容器:
- 支持依赖关系管理
- 支持注册完成回调
- 自动解析依赖顺序
### 注册查询
- `Contains(Type type)` / `Contains<T>()`
- `Get(Type type)` / `Get<T>()`
## 事件系统
### 消息监听
- `AddListener<Signal>(Type slot, Action<Signal> listener)`
- `SendMessage(Type slot, ISignal signal)`
- `SendMessage<Signal>(Signal signal)`
提供类型安全的事件分发机制:
- 支持按类型注册监听器
- 支持泛型消息类型
- 自动管理监听器生命周期
### Listening类
监听器管理类,提供:
- `StopListening()` 停止监听
## 时间线系统
### 时间线管理
- `CreateTimeline()` 创建新的时间线
- `AddStep(int timelineId, Func<bool> predicate, params Action[] actions)` 添加步骤
- `UpdateTimeline()` 更新所有时间线
- `ResetTimelineContext(int timelineId)` 重置时间线上下文
提供基于条件的任务调度:
- 支持多条时间线并行执行
- 基于谓词的条件触发
- 支持动态添加执行步骤
## 类型格式化
### 类型序列化
- `FormatType(Type type)` 格式化类型为字符串
- `LoadFromFormat(string data)` 从字符串加载类型
- `LoadFromFormat(string data, out Exception exception)` 安全加载类型
使用格式:`Assembly::FullTypeName`
## 内部管理
### 系统重置
- `InternalReset()` 重置所有内部状态
清理以下组件:
- 注册历史
- 未完成的目标
- 完成器回调
- 依赖关系
- 子对象容器
- 事件监听器
- 时间线队列

View File

@@ -0,0 +1,49 @@
[返回](./Runtime-README.md)
# /Convention/Runtime/Config
---
包含了关于静态的配置信息等内容, 并且引入全体标准库内容
## Import All
检查并尝试引入所有依赖库
## 静态配置
若不存在相应配置, 则需要定义
- `CURRENT_COM_NAME` 公司/组织名称
- `CURRENT_APP_NAME` 应用名称
## PlatformIndicator包含的内容
- `IsRelease` Debug/Release状态
- `IsPlatform<Name>` 平台判断
- `IsPlatformX64`平台架构判断
- 编译器/解释器判断 如`IsMSVC`
- `ApplicationPath` 获取当前应用程序目录
- `StreamingAssetsPath` 获取StreamingAssets目录
- `PersistentPath` 获取持久化目录
- `PlatformInfomation` 平台相关的发布信息
## 多个静态类 <Type>Indicator
包含对应类型常用的工具函数
## 静态类 DescriptiveIndicator
包含一个`描述`字符串, 可选一个`值`对象
## 其他基础内容
用于对齐不同语言间基本实现的颗粒度, 如以下内容
- 类型转换
- 字符串操作
- Construct/Destruct 重构造/析构
- 命令行解析
- 简单的反射内容
- 元类型
- 等等...

View File

@@ -0,0 +1,278 @@
from types import TracebackType
from typing import *
from abc import *
import sys
import threading
import traceback
import datetime
import platform
import time
from colorama import Fore as ConsoleFrontColor, Back as ConsoleBackgroundColor, Style as ConsoleStyle
def format_traceback_info(char:str='\n', back:int=1):
return char.join(traceback.format_stack()[:-back])
INTERNAL_DEBUG = False
def SetInternalDebug(mode:bool):
global INTERNAL_DEBUG
INTERNAL_DEBUG = mode
def GetInternalDebug() -> bool:
global INTERNAL_DEBUG
return INTERNAL_DEBUG
def print_colorful(color:str, *args, is_reset:bool=True, **kwargs):
with lock_guard():
if is_reset:
print(color,*args,ConsoleStyle.RESET_ALL, **kwargs)
else:
print(color,*args, **kwargs)
ImportingFailedSet:Set[str] = set()
def ImportingThrow(
ex: ImportError,
moduleName: str,
requierds: Sequence[str],
*,
messageBase: str = ConsoleFrontColor.RED+"{module} Module requires {required} package."+ConsoleFrontColor.RESET,
installBase: str = ConsoleFrontColor.GREEN+"\tpip install {name}"+ConsoleFrontColor.RESET
):
with lock_guard():
requierds_str = ",".join([f"<{r}>" for r in requierds])
print(messageBase.format_map(dict(module=moduleName, required=requierds_str)))
print('Install it via command:')
for i in requierds:
global ImportingFailedSet
ImportingFailedSet.add(i)
install = installBase.format_map({"name":i})
print(install)
if ex:
print(ConsoleFrontColor.RED, f"Import Error On {moduleName} Module: {ex}, \b{ex.path}\n"\
f"[{ConsoleFrontColor.RESET}{format_traceback_info(back=2)}{ConsoleFrontColor.RED}]")
def InternalImportingThrow(
moduleName: str,
requierds: Sequence[str],
*,
messageBase: str = ConsoleFrontColor.RED+"{module} Module requires internal Convention package: {required}."+ConsoleFrontColor.RESET,
):
with lock_guard():
requierds_str = ",".join([f"<{r}>" for r in requierds])
print(f"Internal Convention package is not installed.\n{messageBase.format_map({
"module": moduleName,
"required": requierds_str
})}\n[{ConsoleFrontColor.RESET}{format_traceback_info(back=2)}{ConsoleFrontColor.RED}]")
def ReleaseFailed2Requirements():
global ImportingFailedSet
if len(ImportingFailedSet) == 0:
return
with open("requirements.txt", 'w') as f:
f.write("\n".join(ImportingFailedSet))
try:
from pydantic import *
except ImportError:
InternalImportingThrow("Internal", ["pydantic"])
type Typen[_T] = type
type Action[_T] = Callable[[_T], None]
type Action2[_T1, _T2] = Callable[[_T1, _T2], None]
type Action3[_T1, _T2, _T3] = Callable[[_T1, _T2, _T3], None]
type Action4[_T1, _T2, _T3, _T4] = Callable[[_T1, _T2, _T3, _T4], None]
type Action5[_T1, _T2, _T3, _T4, _T5] = Callable[[_T1, _T2, _T3, _T4, _T5], None]
type ActionW = Callable[[Sequence[Any]], None]
type ClosuresCallable[_T] = Union[Callable[[Optional[None]], _T], Typen[_T]]
def AssemblyTypen(obj:Any) -> str:
if isinstance(obj, type):
return f"{obj.__module__}.{obj.__name__}, "\
f"{obj.Assembly() if hasattr(obj, "Assembly") else "Global"}"
else:
return f"{obj.__class__.__module__}.{obj.__class__.__name__}, "\
f"{obj.GetAssembly() if hasattr(obj, "GetAssembly") else "Global"}"
def ReadAssemblyTypen(
assembly_typen: str,
*,
premodule: Optional[str|Callable[[str], str]] = None
) -> Tuple[type, str]:
typen, assembly_name = assembly_typen.split(",")
module_name, _, class_name = typen.rpartition(".")
if premodule is not None:
if isinstance(premodule, str):
module_name = premodule
else:
module_name = premodule(module_name)
import importlib
target_type = getattr(importlib.import_module(module_name), class_name)
return target_type, assembly_name
# using as c#: event
class ActionEvent[_Call:Callable]:
def __init__(self, actions:Sequence[_Call]):
super().__init__()
self.__actions: List[Callable] = [action for action in actions]
self.call_indexs: List[int] = [i for i in range(len(actions))]
self.last_result: List[Any] = []
def CallFuncWithoutCallIndexControl(self, index:int, *args, **kwargs) -> Union[Any, Exception]:
try:
return self.__actions[index](*args, **kwargs)
except Exception as ex:
return ex
def CallFunc(self, index:int, *args, **kwargs) -> Union[Any, Exception]:
return self.CallFuncWithoutCallIndexControl(self.call_indexs[index], *args, **kwargs)
def _inject_invoke(self, *args, **kwargs):
result:List[Any] = []
for index in range(self.call_max_count):
result.append(self.CallFunc(index, *args, **kwargs))
return result
def Invoke(self, *args, **kwargs) -> Union[Self, bool]:
self.last_result = self._inject_invoke(*args, **kwargs)
return self
def InitCallIndex(self):
self.call_indexs = [i for i in range(len(self.__actions))]
def AddAction(self, action:_Call):
self.__actions.append(action)
self.call_indexs.append(len(self.__actions)-1)
return self
def AddActions(self, actions:Sequence[_Call]):
for action in actions:
self.AddAction(action)
return self
def _InternalRemoveAction(self, action:_Call):
if action in self.__actions:
index = self.__actions.index(action)
self.__actions.remove(action)
self.call_indexs.remove(index)
for i in range(len(self.call_indexs)):
if self.call_indexs[i] > index:
self.call_indexs[i] -= 1
return True
return False
def RemoveAction(self, action:_Call):
while self._InternalRemoveAction(action):
pass
return self
def IsValid(self):
return not any(isinstance(x, Exception) for x in self.last_result)
def __bool__(self):
return self.IsValid()
@property
def CallMaxCount(self):
return len(self.call_indexs)
@property
def ActionCount(self):
return len(self.__actions)
# region instance
# threads
class atomic[_T]:
def __init__(
self,
value: _T,
locker: Optional[threading.Lock] = None,
) -> None:
self._value: _T = value
self._is_in_with: bool = False
self.locker: threading.Lock = locker if locker is not None else threading.Lock()
def FetchAdd(self, value:_T):
with lock_guard(self.locker):
self._value += value
return self._value
def FetchSub(self, value:_T):
with lock_guard(self.locker):
self._value -= value
return self._value
def Load(self) -> _T:
with lock_guard(self.locker):
return self._value
def Store(self, value: _T):
with lock_guard(self.locker):
self._value = value
def __add__(self, value:_T):
return self.FetchAdd(value)
def __sub__(self, value:_T):
return self.FetchSub(value)
def __iadd__(self, value:_T) -> Self:
self.FetchAdd(value)
return self
def __isub__(self, value:_T) -> Self:
self.FetchSub(value)
return self
def __enter__(self) -> Self:
self._is_in_with = True
self.locker.acquire()
return self
def __exit__(
self,
exc_type: Optional[type],
exc_val: Optional[BaseException],
exc_tb: Optional[TracebackType]
) -> bool:
self._is_in_with = False
self.locker.release()
if exc_type is None:
return True
else:
return False
@property
def Value(self) -> _T:
if self._is_in_with:
return self._value
raise NotImplementedError("This method can only be called within a with statement")
@Value.setter
def Value(self, value:_T) -> _T:
if self._is_in_with:
self._value = value
raise NotImplementedError("This method can only be called within a with statement")
def __str__(self) -> str:
return str(self.Load())
def __repr__(self) -> str:
return repr(self.Load())
InternalGlobalLocker = threading.Lock()
InternalGlobalLockerCount = atomic[int](0)
class lock_guard:
def __init__(
self,
lock: Optional[Union[threading.RLock, threading.Lock]] = None
):
if lock is None:
lock = InternalGlobalLocker
self._locker = lock
self._locker.acquire()
def __del__(self):
self._locker.release()
class global_lock_guard(lock_guard):
def __init__(self):
super().__init__(None)
class thread_instance(threading.Thread):
def __init__(
self,
call: Action[None],
*,
is_del_join: bool = True,
**kwargs
):
kwargs.update({"target": call})
super().__init__(**kwargs)
self.is_del_join = is_del_join
self.start()
def __del__(self):
if self.is_del_join:
self.join()
# region end
def Nowf() -> str:
'''
printf now time to YYYY-MM-DD_HH-MM-SS format,
return: str
'''
return datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")

View File

@@ -0,0 +1,111 @@
[返回](./Runtime-README.md)
# /Convention/Runtime/EasySave
---
完整的序列化和数据持久化系统,提供易用的数据存储和读取功能
## 核心特性
### 支持的数据格式
- **EasySave - JSON** 支持多态的json格式
- **Binary** 紧凑的二进制格式
## EasySave主类
### 基本保存操作
#### 泛型保存
- `Save<T>(string key, T value)` 保存到默认文件
- `Save<T>(string key, T value, string filePath)` 保存到指定文件
- `Save<T>(string key, T value, EasySaveSettings settings)` 使用自定义设置
#### 原始数据保存
- `SaveRaw(byte[] bytes)` / `SaveRaw(string str)` 保存原始数据
- `AppendRaw(byte[] bytes)` / `AppendRaw(string str)` 追加原始数据
### 基本加载操作
#### 泛型加载
- `Load<T>(string key)` 从默认文件加载
- `Load<T>(string key, string filePath)` 从指定文件加载
- `Load<T>(string key, T defaultValue)` 带默认值的安全加载
#### 原始数据加载
- `LoadRawBytes()` / `LoadRawString()` 加载原始数据
- `LoadString(string key, string defaultValue)` 加载字符串
#### 加载到现有对象
- `LoadInto<T>(string key, T obj)` 将数据加载到现有对象
- `LoadInto(string key, string filePath, object obj)` 从指定文件加载到对象
### 序列化操作
#### 内存序列化
- `Serialize<T>(T value, EasySaveSettings settings = null)` 序列化为字节数组
- `Deserialize<T>(byte[] bytes, EasySaveSettings settings = null)` 从字节数组反序列化
- `DeserializeInto<T>(byte[] bytes, T obj)` 反序列化到现有对象
### 加密和压缩
#### 加密操作
- `EncryptBytes(byte[] bytes, string password = null)` 加密字节数组
- `DecryptBytes(byte[] bytes, string password = null)` 解密字节数组
- `EncryptString(string str, string password = null)` 加密字符串
- `DecryptString(string str, string password = null)` 解密字符串
#### 压缩操作
- `CompressBytes(byte[] bytes)` 压缩字节数组
- `DecompressBytes(byte[] bytes)` 解压字节数组
- `CompressString(string str)` 压缩字符串
- `DecompressString(string str)` 解压字符串
### 备份系统
#### 备份操作
- `CreateBackup()` / `CreateBackup(string filePath)` 创建备份
- `RestoreBackup(string filePath)` 恢复备份
#### 时间戳
- `GetTimestamp()` / `GetTimestamp(string filePath)` 获取文件时间戳
### 缓存系统
#### 缓存操作
- `StoreCachedFile()` / `StoreCachedFile(string filePath)` 存储缓存文件
- `CacheFile()` / `CacheFile(string filePath)` 缓存文件
## EasySaveSettings配置
### 枚举类型定义
#### 存储位置
```csharp
public enum Location { File, InternalMS, Cache }
```
#### 目录类型
```csharp
public enum Directory { PersistentDataPath, DataPath }
```
#### 加密类型
```csharp
public enum EncryptionType { None, AES }
```
#### 压缩类型
```csharp
public enum CompressionType { None, Gzip }
```
#### 数据格式
```csharp
public enum Format { JSON }
```
#### 引用模式
```csharp
public enum ReferenceMode { ByRef, ByValue, ByRefAndValue }
```

View File

@@ -0,0 +1,88 @@
[返回](./Runtime-README.md)
# /Convention/Runtime/File
---
文件操作工具模块,提供跨平台的文件和目录操作功能
## ToolFile类
### 构造与基本信息
- `ToolFile(string path)` 从路径创建文件对象
- `ToString()` / `GetFullPath()` 获取完整路径
- `GetName(bool is_ignore_extension = false)` 获取文件名
- `GetExtension()` 获取文件扩展名
### 路径操作
- `ToolFile operator |(ToolFile left, string rightPath)` 路径连接操作符
- `Open(string path)` 打开指定路径
- `Open(FileMode mode)` 以指定模式打开文件
- `Close()` 关闭文件流
- `BackToParentDir()` 回到父目录
- `GetParentDir()` 获取父目录
### 存在性检查
- `Exists()` 检查文件或目录是否存在
- `implicit operator bool` 隐式布尔转换等同于Exists()
### 类型判断
- `IsDir()` 是否为目录
- `IsFile()` 是否为文件
- `IsFileEmpty()` 文件是否为空
### 文件加载
支持多种格式的文件读取:
#### JSON操作
- `LoadAsRawJson<T>()` 原始JSON反序列化
- `LoadAsJson<T>(string key = "data")` 使用EasySave加载JSON
#### 文本操作
- `LoadAsText()` 加载为文本字符串
#### 二进制操作
- `LoadAsBinary()` 加载为字节数组
### 文件保存
支持多种格式的文件写入:
#### JSON保存
- `SaveAsRawJson<T>(T data)` 原始JSON序列化保存
- `SaveAsJson<T>(T data, string key)` 使用EasySave保存JSON
#### 二进制保存
- `SaveAsBinary(byte[] data)` 保存字节数组
- `SaveDataAsBinary(string path, byte[] outdata, FileStream Stream = null)` 静态二进制保存
### 文件操作
- `Create()` 创建文件或目录
- `Rename(string newPath)` 重命名
- `Move(string path)` 移动文件
- `Copy(string path, out ToolFile copyTo)` 复制文件
- `Delete()` / `Remove()` 删除文件或目录
- `Refresh()` 刷新文件信息
### 路径管理
- `MustExistsPath()` 确保路径存在(自动创建)
- `TryCreateParentPath()` 尝试创建父路径
### 目录操作
- `DirIter()` 遍历目录获取字符串列表
- `DirToolFileIter()` 遍历目录获取ToolFile列表
- `DirCount()` 获取目录内项目数量
- `DirClear()` 清空目录内容
- `MakeFileInside(string source, bool isDeleteSource = false)` 在目录内创建文件
### 文件对话框(平台相关)
- `SelectMultipleFiles(string filter, string title)` 多文件选择对话框
- `SelectFile(string filter, string title)` 单文件选择对话框
- `SaveFile(string filter, string title)` 保存文件对话框
- `SelectFolder(string description)` 文件夹选择对话框
### 文件浏览
- `BrowseFile(params string[] extensions)` 浏览指定扩展名的文件
- `BrowseToolFile(params string[] extensions)` 浏览并返回ToolFile对象
### 时间戳
- `GetTimestamp()` 获取文件时间戳

View File

@@ -0,0 +1,88 @@
[返回](./Runtime-README.md)
# /Convention/Runtime/GlobalConfig
---
全局配置管理模块,提供配置文件操作、日志系统和项目级配置管理
## GlobalConfig类
### 构造与初始化
- `GlobalConfig(string dataDir, bool isTryCreateDataDir = false, bool isLoad = true)`
- `GlobalConfig(ToolFile dataDir, bool isTryCreateDataDir = false, bool isLoad = true)`
#### 初始化流程
1. 设置数据目录,确保目录存在
2. 检查配置文件,不存在则生成空配置
3. 可选自动加载现有配置
### 静态配置
- `ConstConfigFile` 配置文件名(默认"config.json"
- `InitExtensionEnv()` 初始化扩展环境
- `GenerateEmptyConfigJson(ToolFile file)` 生成空配置JSON
### 文件管理
- `GetConfigFile()` / `ConfigFile` 获取配置文件对象
- `GetFile(string path, bool isMustExist = false)` 获取数据目录下的文件
- `CreateFile(string path)` 创建文件
- `EraseFile(string path)` 清空文件内容
- `RemoveFile(string path)` 删除文件
### 配置数据操作
能够被`foreach`/`for`使用迭代器历遍配置内容的键值对
#### 数据访问
- `operator[](string key)` 索引器访问配置项
- `Contains(string key)` 检查键是否存在
- `Remove(string key)` 删除配置项
- `DataSize()` 获取配置项数量
#### 持久化
- `SaveProperties()` 保存配置到文件
- `LoadProperties()` 从文件加载配置
配置文件格式:
```json
{
"properties": {
"key1": "value1",
"key2": "value2"
}
}
```
### 日志系统
- `GetLogFile()` / `LogFile` 获取日志文件对象
- `DefaultLogger` 默认日志输出器(可自定义)
#### 日志方法
- `Log(string messageType, string message, Action<string> logger)`
- `Log(string messageType, string message)` 使用默认日志器
- `LogPropertyNotFound(string message, Action<string> logger, object @default = null)`
- `LogPropertyNotFound(string message, object @default = null)`
- `LogMessageOfPleaseCompleteConfiguration()` 记录配置提示信息
#### 日志格式
```
[time] MessageType : Message
```
自动调整消息类型的对齐宽度
### 配置查找
- `FindItem(string key, object @default = null)` 查找配置项,支持默认值
## ProjectConfig类
继承自 `GlobalConfig`,专门用于项目级配置管理
### 静态配置
- `ProjectConfigFileFocus` 项目配置目录焦点(默认"Assets/"
- `InitExtensionEnv()` 初始化项目扩展环境
- `SetProjectConfigFileFocus(string path)` 设置项目配置焦点目录
- `GetProjectConfigFileFocus()` 获取项目配置焦点目录
### 构造
- `ProjectConfig(bool isLoad = true)` 使用默认项目目录构造

View File

@@ -0,0 +1,7 @@
[返回](./Runtime-README.md)
# /Convention/Runtime/Math
---
数学工具模块,提供常用数学计算功能

View File

@@ -0,0 +1,7 @@
[返回](./Runtime-README.md)
# /Convention/Runtime/Plugins
---
插件系统模块,提供扩展机制和平台特定功能

121
Convention/Runtime/Web.md Normal file
View File

@@ -0,0 +1,121 @@
[返回](./Runtime-README.md)
# /Convention/Runtime/Web
---
网络工具模块提供HTTP客户端和URL操作功能
## ToolURL类
### 构造与基本信息
- `ToolURL(string url)` 从URL字符串创建对象
- `ToString()` / `GetFullURL()` / `FullURL` 获取完整URL
- `implicit operator string` 隐式字符串转换
### URL属性解析
- `GetFilename()` 获取URL中的文件名
- `GetExtension()` 获取文件扩展名
- `ExtensionIs(params string[] extensions)` 检查扩展名是否匹配
### URL验证
- `IsValid` 属性检查URL是否有效
- `ValidateURL()` 验证URL格式
- `implicit operator bool` 隐式布尔转换等同于IsValid
支持HTTP和HTTPS协议的绝对URL
### HTTP方法
#### GET请求
- `GetAsync(Action<HttpResponseMessage> callback)` 异步GET
- `Get(Action<HttpResponseMessage> callback)` 同步GET
#### POST请求
- `PostAsync(Action<HttpResponseMessage> callback, Dictionary<string, string> formData = null)` 异步POST
- `Post(Action<HttpResponseMessage> callback, Dictionary<string, string> formData = null)` 同步POST
支持表单数据提交
### 内容加载
#### 文本加载
- `LoadAsTextAsync()` 异步加载为文本
- `LoadAsText()` 同步加载为文本
#### 二进制加载
- `LoadAsBinaryAsync()` 异步加载为字节数组
- `LoadAsBinary()` 同步加载为字节数组
#### JSON加载
- `LoadAsJson<T>()` 同步加载并反序列化JSON
- `LoadAsJsonAsync<T>()` 异步加载并反序列化JSON
### 文件保存
- `Save(string localPath = null)` 自动选择格式保存到本地
- `SaveAsText(string localPath = null)` 保存为文本文件
- `SaveAsJson(string localPath = null)` 保存为JSON文件
- `SaveAsBinary(string localPath = null)` 保存为二进制文件
### 文件类型判断
- `IsText` 是否为文本文件txt, html, htm, css, js, xml, csv
- `IsJson` 是否为JSON文件
- `IsImage` 是否为图像文件jpg, jpeg, png, gif, bmp, svg
- `IsDocument` 是否为文档文件pdf, doc, docx, xls, xlsx, ppt, pptx
### 高级操作
- `Open(string url)` 在当前对象上打开新URL
- `DownloadAsync(string localPath = null)` 异步下载文件
- `Download(string localPath = null)` 同步下载文件
## 设计特点
### 统一的HTTP客户端
使用静态 `HttpClient` 实例,避免连接池耗尽
### 自动内容类型检测
基于文件扩展名自动判断内容类型,优化保存和处理策略
### 异步支持
所有网络操作都提供异步和同步两种版本
### 错误处理
网络请求失败时回调函数接收null参数方法返回false
### 文件管理集成
下载的文件自动转换为ToolFile对象与文件系统模块无缝集成
### 灵活的数据格式
支持文本、二进制、JSON等多种数据格式的加载和保存
## 使用示例
### 基本HTTP请求
```csharp
var url = new ToolURL("https://api.example.com/data");
if (url.IsValid)
{
url.Get(response => {
if (response != null && response.IsSuccessStatusCode)
{
// 处理响应
}
});
}
```
### 文件下载
```csharp
var url = new ToolURL("https://example.com/file.json");
var localFile = url.Download("./downloads/file.json");
if (localFile.Exists())
{
var data = localFile.LoadAsJson<MyDataType>();
}
```
### 类型安全的JSON加载
```csharp
var url = new ToolURL("https://api.example.com/users.json");
var users = url.LoadAsJson<List<User>>();
```

View File