强化基础 Action ac = (System.Action)delegate() { Console.WriteLine("123456")...

博客指出委托间能够相互转换,这是信息技术领域中关于委托特性的一个关键信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

委托间 也是 可以相互转换的

using System.Collections; using System.Threading; using System.Collections.Generic; using System.IO; //using System.Diagnostics; //using System.Net; using System; using UnityEngine; using XLua; using LitJson; public class ThreadEvent { public string Key; public List<object> evParams = new List<object>(); } public class HasLoadFile { public string Key; public string KeyValue; public string FileVersionPath; public string FilePath; public LuaFunction onFinish; } public class NotiData { public string evName; public object evParam; public NotiData(string name, object param) { this.evName = name; this.evParam = param; } } namespace LuaFramework { [LuaCallCSharp] public class DownloadManager : Manager { private Thread thread; private Action func; private LuaFunction luaFinishCall; //private Stopwatch sw = new Stopwatch(); private string currDownFile = string.Empty; private ThreadEvent currentEvent; static readonly object m_lockObj = new object(); static Queue<ThreadEvent> events = new Queue<ThreadEvent>(); static Queue<HasLoadFile> hasLoadFile = new Queue<HasLoadFile>(); private bool UIisDownloading = false; //下载大厅 private bool GameisDownloading = false; //下载游戏 private bool isDownloadGameFailure = false;//下载失败 private bool isNowUnZipFile = false; //正在解压文件 private bool isNowUnZipFileComplise = false; //解压完成 public LuaFunction onUnZipFinishCall; //解压完成回调 private int tryDownloadTimes = 0; //当前已经尝试下载的次数 private int totalDownFileNum = 0;//总需下载的文件数 private int waitUnZipFileNum = 0;//总下载的文件数 private int hasUnZipFileNum = 0;//已解压的文件数 HttpDownLoader downloader; private Action<float> onProgressAction; private Action<string> onFileProgressAction; private Action<string> onUnZipFileCall; private LuaFunction onProgressLuaFunc; private static DownloadManager _instance; //private GameObject messagePanel; //private UILabel messageTxt; private Dictionary<string, string> m_localFileVersion; private string m_localFileVersionPath; public static DownloadManager Instance { get { return _instance; } } void Awake() { _instance = this; } // Use this for initialization void Start() { } public void checkUpdate(LuaFunction callBack) { StartCoroutine(_checkUpdate(callBack)); } public void SaveLocalVersion() { string output = ""; foreach (KeyValuePair<string, string> kv in m_localFileVersion) { output += kv.Key + "|" + kv.Value + "\n"; } StreamWriter sw = new StreamWriter(m_localFileVersionPath); sw.Write(output); sw.Close(); } IEnumerator _checkUpdate(LuaFunction callBack) { string uiV = "gameui" + AppConst.UIVersion; string VersionUrl;//下载版本信息 if (AppConst.EOSType == 3) { VersionUrl = AppConst.ResUrl + "/android/"+ uiV + "/files.txt"; }else if (AppConst.EOSType == 5) { VersionUrl = AppConst.ResUrl + "/ios/" + uiV +"/files.txt"; } else { VersionUrl = AppConst.ResUrl + "/pc/" + uiV +"/files.txt"; } WWW www = new WWW(VersionUrl); yield return www; if (www.error == null) { string filesText = System.Text.Encoding.Default.GetString(www.bytes); string[] files = filesText.Split('\n'); for (int i = 0; i < files.Length; i++) { string[] keyValue = files[i].Split('|'); string f = keyValue[0].Replace(".zip", ""); string vers = keyValue[1].Replace("\r", ""); string direc = AppConst.FrameworkRoot + "/" + uiV + "/" + f; if (!Directory.Exists(direc)) //如果游戏没存在则不理 { //callBack.Call("f",false); } else { string version = ""; string localFilesPath = AppConst.FrameworkRoot + "/" + uiV + "/" + f + "/version.txt"; if (File.Exists(localFilesPath)) { StreamReader sr = new StreamReader(localFilesPath); version = sr.ReadToEnd(); sr.Close(); if (version == vers) { callBack.Call(f,true); } else { callBack.Call(f,false); } } else { callBack.Call(f,false); } } } } www.Dispose(); } public void downloadFiles(string filesText, Action<string> onProgress,Action<string> OnUnZipFile) { onUnZipFileCall = OnUnZipFile; onFileProgressAction = onProgress; _downloadFiles(filesText); //StartCoroutine(_downloadFiles(filesText)); } public void downLoadGame(string gameId, LuaFunction onProgress, LuaFunction onFinish, LuaFunction onFail) { _downLoadGame(gameId, onProgress, onFinish, onFail); } void _downLoadGame(string gameId, LuaFunction onProgress, LuaFunction onFinish, LuaFunction onFail) { string uiV = "gameui" + AppConst.UIVersion; string osType; if (AppConst.EOSType == 3) { osType = "/android"; }else if (AppConst.EOSType == 5) { osType = "/ios"; }else { osType = "/pc"; } string uidirec = AppConst.FrameworkRoot + "/"+ uiV; if (!Directory.Exists(uidirec)) { Directory.CreateDirectory(uidirec); } string direc = AppConst.FrameworkRoot + "/"+ uiV +"/" + gameId; if (Directory.Exists(direc)) { Directory.Delete(direc, true); } string fileUrl = AppConst.ResUrl + osType + "/"+ uiV+ "/" + gameId.Trim() + ".zip"; string localfile = AppConst.FrameworkRoot + "/" + uiV + "/" + gameId.Trim() + ".zip"; object[] param = new object[5] { fileUrl, localfile , onProgress , onFinish , onFail }; ThreadEvent ev = new ThreadEvent(); ev.Key = NotiConst.UPDATE_DOWNLOAD; ev.evParams.AddRange(param); DownloadManager.AddEvent(ev); StartDownloadGame(); } public void downloadFilesLuaCall(string filesUrlDir, string localFilesDir, LuaFunction onProgress) { //onProgressLuaFunc = onProgress; //StartCoroutine(_downloadFiles(filesUrlDir, localFilesDir)); } private ConfigInfo _gamecode; private Action<float> _onProgress; private Action<string> _onFinish; public void downloadGamecode(ConfigInfo gamecode, Action<float> onProgress, Action<string> onFinish) { _gamecode = gamecode; _onProgress = onProgress; _onFinish = onFinish; downloader = HttpDownLoader.newHttpDownLoader(); string osType; string fileUrl; string localFile = ""; if (AppConst.EOSType == 3) { osType = "android"; fileUrl = gamecode.Android_DownLoadurl; localFile = AppConst.FrameworkRoot + "Dating" + AppConst.GameCode + ".apk"; } else if (AppConst.EOSType == 5) { osType = "ios"; fileUrl = gamecode.Ios_DownLoadurl; Application.OpenURL(fileUrl); return; } else {//暂未发布PC osType = "pc"; fileUrl = gamecode.PC_DownLoadurl; } downloader.Init(fileUrl, localFile, (float percent) => { onProgress(percent); }, (string savePath) => { onFinish(savePath); _onProgress = null; _onFinish = null; }, OnDownloadGameVersionFailed); } //IEnumerator _downloadFiles(string filesText) void _downloadFiles(string filesText) { //string VersionUrl = AppConst.ResUrl + filesUrlDir + "/files2.txt"; //WWW www = new WWW(VersionUrl); //yield return www; //if (www.error == null) //{ totalDownFileNum = 0; string localFilesText = string.Empty; //string localFilesPath = AppConst.FrameworkRoot + localFilesDir + "/files2.txt"; string localFilesPath = AppConst.FrameworkRoot + "/files2.txt"; Dictionary<string, string> filesVersionDic = new Dictionary<string, string>(); //本地是否有版本文件 if (File.Exists(localFilesPath)) { StreamReader sr = new StreamReader(localFilesPath); localFilesText = sr.ReadToEnd(); localFilesText = localFilesText.Replace("\r", ""); sr.Close(); string[] _files = localFilesText.Split('\n'); if (_files.Length > 1) { for (int i = 0; i < _files.Length; i++) { string[] _keyValue = _files[i].Split('|'); if(_keyValue.Length >= 2) { if (!filesVersionDic.ContainsKey(_keyValue[0])) { filesVersionDic.Add(_keyValue[0], _keyValue[1]); } } } } }else//创建版本文件 { var file = File.Create(localFilesPath); file.Close(); } m_localFileVersionPath = localFilesPath; m_localFileVersion = filesVersionDic; //string filesText = System.Text.Encoding.Default.GetString(www.bytes); var js = JsonMapper.ToObject(filesText); foreach(var key in js.Keys) { bool canUpdate = true; string versionStr; string dicKey = key; if (key == "FishAudio") { #if UNITY_ANDROID versionStr = js[key]["android"][AppConst.UIVersion].ToString(); dicKey = "android/" + key + "_" + AppConst.UIVersion; #elif UNITY_IPHONE versionStr = js[key]["ios"][AppConst.UIVersion].ToString(); dicKey = "ios/" + key + "_" + AppConst.UIVersion; #endif } else if (key == "datingui") { #if UNITY_ANDROID versionStr = js[key]["android"][AppConst.UIVersion].ToString(); dicKey = "android/" + key + "_" + AppConst.UIVersion; #elif UNITY_IPHONE versionStr = js[key]["ios"][AppConst.UIVersion].ToString(); dicKey = "ios/" + key + "_" + AppConst.UIVersion; #endif } else { versionStr = js[key].ToString(); } if (filesVersionDic.ContainsKey(dicKey) && versionStr == filesVersionDic[dicKey]) { canUpdate = false; } if (canUpdate) { totalDownFileNum = totalDownFileNum + 1; string path = AppConst.FrameworkRoot + "/" + dicKey; if (Directory.Exists(path)) { Directory.Delete(path, true); } string fileUrl = AppConst.ResUrl + "/" + dicKey + ".zip"; string localfile = AppConst.FrameworkRoot + "/" + key + ".zip";// + "_" + AppConst.UIVersion object[] param = new object[4] { fileUrl, localfile, dicKey, versionStr}; ThreadEvent ev = new ThreadEvent(); ev.Key = NotiConst.UPDATE_DOWNLOAD; ev.evParams.AddRange(param); DownloadManager.AddEvent(ev); } } //} StartDownloadUI(); } public void getWWW(string url, LuaFunction callBack = null) { StartCoroutine(_getWWW(url, callBack)); } IEnumerator _getWWW(string url, LuaFunction callBack = null) { if (url.Equals(string.Empty)) { yield return null; } WWW www = new WWW(url); yield return www; if (callBack != null) callBack.Call(www); www.Dispose(); } /// <summary> /// 添加到事件队列 /// </summary> public void AddEvent(ThreadEvent ev) { events.Enqueue(ev); } public void OnFinish(Action func) { this.func = func; } public void StartDownloadUI() { if (AppConst.EOSType == 3 || AppConst.EOSType == 5 ) { //友盟统计 UnityCallAndroid.Instance.CallAndroid("umenRecord","140"); } UIisDownloading = true; } public void StartDownloadGame() { GameisDownloading = true; } // Update is called once per frame void Update() { if (UIisDownloading) { if (isNowUnZipFile) { if (onUnZipFileCall != null) { string str = "正在解压文件:"+ hasUnZipFileNum.ToString() + "/" + waitUnZipFileNum.ToString(); onUnZipFileCall(str); } return; } if (!currDownFile.Equals(string.Empty)) { return; } if (events.Count == 0) { //下载完成先安装 if (hasLoadFile.Count > 0) { isNowUnZipFile = true; System.GC.Collect(); UnZipFile(); return; } else { if (thread != null) { thread.Abort(); thread.Join(); thread = null; } } if (this.func != null) { this.func(); this.func = null; if (AppConst.EOSType == 3 || AppConst.EOSType == 5 ) { //友盟统计 UnityCallAndroid.Instance.CallAndroid("umenRecord","141"); } } if (luaFinishCall != null) { luaFinishCall.Call(); luaFinishCall = null; } onProgressLuaFunc = null; onProgressAction = null; onFileProgressAction = null; onUnZipFileCall = null; UIisDownloading = false; currentEvent = null; isNowUnZipFile = false; waitUnZipFileNum = 0; hasUnZipFileNum = 0; System.GC.Collect(); return; } System.GC.Collect(); tryDownloadTimes = 0; currentEvent = events.Dequeue(); OnDownloadFile(currentEvent.evParams); } if (GameisDownloading) { if (isNowUnZipFile) { if (isNowUnZipFileComplise) { if (onUnZipFinishCall != null) { onUnZipFinishCall.Call(); } isNowUnZipFileComplise = false; } return; } if (!currDownFile.Equals(string.Empty)) { return; } if (Application.internetReachability == NetworkReachability.NotReachable) { return; } else { } //下载一个安装一个 if (hasLoadFile.Count > 0) { isNowUnZipFile = true; System.GC.Collect(); InstantceGame(); return; } else { if (thread != null) { thread.Abort(); thread.Join(); thread = null; } } if (events.Count == 0 ) { GameisDownloading = false; currentEvent = null; System.GC.Collect(); return; } System.GC.Collect(); tryDownloadTimes = 0; currentEvent = events.Dequeue(); OnDownloadGame(); } } IEnumerator tryDownloadGames() { System.GC.Collect(); yield return new WaitForSeconds(1.0f); downloader = null; OnDownloadGame(); } /// <summary> ///下载游戏 /// <summary> void OnDownloadGame() { string url = currentEvent.evParams[0].ToString(); currDownFile = currentEvent.evParams[1].ToString(); LuaFunction onProgress = (LuaFunction)currentEvent.evParams[2]; LuaFunction onFinish = (LuaFunction)currentEvent.evParams[3]; LuaFunction onFail = (LuaFunction)currentEvent.evParams[4]; downloader = HttpDownLoader.newHttpDownLoader(); downloader.Init(url, currDownFile, (float percent) => { onProgress.Call(percent); }, (string savePath) => { HasLoadFile ev = new HasLoadFile(); ev.Key = ""; ev.KeyValue = ""; ev.FileVersionPath = ""; ev.FilePath = savePath; ev.onFinish = onFinish; hasLoadFile.Enqueue(ev); currDownFile = string.Empty; }, () => { tryDownloadTimes = tryDownloadTimes + 1; if (tryDownloadTimes < 20) { StartCoroutine(tryDownloadGames()); //OnDownloadGame(); } else { onFail.Call(); //GameObject msgBox = Instantiate(Resources.Load<GameObject>("MessageBox")); //msgBox.transform.SetParent(GameObject.Find("UI Root").transform); //msgBox.transform.localPosition = Vector3.zero; //msgBox.transform.localScale = Vector3.one; //msgBox.transform.Find("beijing/text").GetComponent<UILabel>().text = "下载游戏失败,是否重新下载?"; //msgBox.transform.Find("queren").GetComponent<UIButton>().onClick.Add(new EventDelegate(() => { // GameObject.Destroy(msgBox); // OnDownloadGame(); //})); //msgBox.transform.Find("quxiao").GetComponent<UIButton>().onClick.Add(new EventDelegate(() => { // GameObject.Destroy(msgBox); // currDownFile = string.Empty; //})); } } ); } /// <summary> /// 下载文件 /// </summary> void OnDownloadFile(List<object> evParams) { string url = evParams[0].ToString(); currDownFile = evParams[1].ToString(); if(evParams.Count == 4) { string key = evParams[2].ToString(); string keyValue = evParams[3].ToString(); downloader = HttpDownLoader.newHttpDownLoader(); downloader.Init(url, currDownFile, ProgressChanged, (string savePath) => { m_localFileVersion[key] = keyValue; HasLoadFile ev = new HasLoadFile(); ev.Key = key; ev.KeyValue = keyValue; ev.FileVersionPath = m_localFileVersionPath; ev.FilePath = savePath; hasLoadFile.Enqueue(ev); waitUnZipFileNum = waitUnZipFileNum + 1; currDownFile = string.Empty; }, OnDownloadFailed); }else { downloader = HttpDownLoader.newHttpDownLoader(); downloader.Init(url, currDownFile, ProgressChanged, OnDownLoadFinish, OnDownloadFailed); } } void OnDownloadGameVersionFailed() { string message = "更新失败!>" + currDownFile; GameObject msgBox = Instantiate(Resources.Load<GameObject>("MessageBox")); msgBox.transform.SetParent(GameObject.Find("UI Root").transform); msgBox.transform.localPosition = Vector3.zero; msgBox.transform.localScale = Vector3.one; msgBox.transform.Find("beijing/text").GetComponent<UILabel>().text = "下载失败,是否重新下载?"; msgBox.transform.Find("queren").GetComponent<UIButton>().onClick.Add(new EventDelegate(() => { downloadGamecode(_gamecode, _onProgress, _onFinish); GameObject.Destroy(msgBox); })); msgBox.transform.Find("quxiao").GetComponent<UIButton>().onClick.Add(new EventDelegate(() => { Application.Quit(); })); } IEnumerator tryDownloads() { System.GC.Collect(); yield return new WaitForSeconds(1.0f); downloader = null; OnDownloadFile(currentEvent.evParams); } void OnDownloadFailed() { tryDownloadTimes = tryDownloadTimes + 1; if (tryDownloadTimes < 10) { StartCoroutine(tryDownloads()); } else { string message = "更新失败!>" + currDownFile; GameObject msgBox = Instantiate(Resources.Load<GameObject>("MessageBox")); msgBox.transform.SetParent(GameObject.Find("UI Root").transform); msgBox.transform.localPosition = Vector3.zero; msgBox.transform.localScale = Vector3.one; msgBox.transform.Find("beijing/text").GetComponent<UILabel>().text = "网络异常,是否重试?"; msgBox.transform.Find("queren").GetComponent<UIButton>().onClick.Add(new EventDelegate(() => { GameObject.Destroy(msgBox); OnDownloadFile(currentEvent.evParams); })); msgBox.transform.Find("quxiao").GetComponent<UIButton>().onClick.Add(new EventDelegate(() => { Application.Quit(); })); } } private void ProgressChanged(float percent) { //UnityEngine.Debug.Log("正在下载" + currDownFile + percent); if (onProgressAction != null) { onProgressAction(percent); } if (onProgressLuaFunc != null) { onProgressLuaFunc.Call(percent); } if (onFileProgressAction != null) { int num = waitUnZipFileNum + 1; string str = string.Format("正在下载文件{0}/{2}:{1:P1},首次更新可能需要等待一些时间",num,percent,totalDownFileNum); onFileProgressAction(str); } //messagePanel.SetActive(true); //messageTxt.text = "正在下载更新文件"; } /// <summary> /// 下载单个文件完成 /// </summary> void OnDownLoadFinish(string savePath) { //小游戏下载完成直接安装 if (savePath.IndexOf(".zip") != -1) { if (ZipFileC.UnZipFile(savePath)) { currDownFile = string.Empty; } else { if (File.Exists(savePath)) { File.Delete(savePath); } currDownFile = string.Empty; } }else { if (File.Exists(savePath)) { File.Delete(savePath); } currDownFile = string.Empty; } } /// <summary> /// 解压文件 /// </summary> void UnZipFile() { thread = new Thread(ThreadRun); thread.Start(); } void ThreadRun() { while (true) { if (hasLoadFile.Count > 0) { HasLoadFile ev = hasLoadFile.Dequeue(); if (ev.FilePath.IndexOf(".zip") != -1) { hasUnZipFileNum = hasUnZipFileNum + 1; //if (onUnZipFileCall != null) //{ // string str = "正在解压文件:"+ hasUnZipFileNum.ToString() + "/" + waitUnZipFileNum.ToString(); // onUnZipFileCall(str); //} if (ZipFileC.UnZipFile(ev.FilePath)) { SaveLocalVersion(); } else { if (File.Exists(ev.FilePath)) { File.Delete(ev.FilePath); } } }else { if (File.Exists(ev.FilePath)) { File.Delete(ev.FilePath); } } } else { isNowUnZipFile = false; break; } Thread.Sleep(1); } } void InstantceGame() { //安装游戏 thread = new Thread(InstanceThreadRun); thread.Start(); } void InstanceThreadRun() { while (true) { if (isNowUnZipFileComplise == false) { if (hasLoadFile.Count > 0) { HasLoadFile ev = hasLoadFile.Dequeue(); if (ev.FilePath.IndexOf(".zip") != -1) { hasUnZipFileNum = hasUnZipFileNum + 1; if (ZipFileC.UnZipFile(ev.FilePath)) { onUnZipFinishCall = null; onUnZipFinishCall = ev.onFinish; isNowUnZipFileComplise = true; //ev.onFinish.Call(); } else { if (File.Exists(ev.FilePath)) { File.Delete(ev.FilePath); } } }else { if (File.Exists(ev.FilePath)) { File.Delete(ev.FilePath); } } } else { isNowUnZipFile = false; break; } } Thread.Sleep(1); } } public void dispose() { //GameObject.Destroy(messagePanel); GameObject.Destroy(gameObject); } /// <summary> /// 应用程序退出 /// </summary> void OnDestroy() { } } }警告 1 变量“osType”已赋值,但其值从未使用过 D:\Lua_Dating546\Assets\Scripts\Manager\DownloadManager.cs 241 20 Assembly-CSharp 错误 2 使用了未赋值的局部变量“versionStr” D:\Lua_Dating546\Assets\Scripts\Manager\DownloadManager.cs 350 64 Assembly-CSharp
07-25
<think>我们正在讨论如何配置System.Threading.Timer的时间间隔。根据用户的问题,他想要设置System.Threading.Timer的刷新时间间隔。在之前的讨论中,我们已经比较了System.Threading.TimerDispatcherTimer的区别,现在需要具体指导如何设置System.Threading.Timer的间隔。 根据引用[1]引用[2]: - System.Threading.Timer使用回调方法,由线程池线程服务。 - 它的构造函数允许设置初始延迟间隔。 具体来说,System.Threading.Timer有多个构造函数,其中一个常用的构造函数签名是: public Timer(TimerCallback callback, object state, int dueTime, int period) 其中: - callback: 定时调用的回调方法(委托) - state: 传递给回调方法的参数(可以为null) - dueTime: 第一次触发回调前的延迟时间(毫秒)。0表示立即开始,Timeout.Infinite表示不开始。 - period: 时间间隔(毫秒)。即每次回调之间的时间间隔。设置为Timeout.Infinite表示只触发一次,不重复。 另一个构造函数允许使用TimeSpan: public Timer(TimerCallback callback, object state, TimeSpan dueTime, TimeSpan period) 因此,设置刷新时间间隔就是设置period参数。 示例: 1. 创建一个每隔1秒(1000毫秒)触发一次的定时器,首次触发延迟0毫秒(立即开始): Timer timer = new Timer(CallbackMethod, null, 0, 1000); 2. 创建一个每隔2秒触发一次,但首次触发延迟5秒: Timer timer = new Timer(CallbackMethod, null, 5000, 2000); 注意:如果需要改变已经创建的Timer的间隔,可以使用Change方法。 timer.Change(dueTime, period); 例如,将上面的定时器改为每隔3秒触发一次,立即开始: timer.Change(0, 3000); 另外,根据引用[3]引用[5],我们需要注意: - 由于回调是在线程池线程上执行的,所以不能直接更新UI控件。如果需要更新UI,必须通过Invoke或BeginInvoke(在WPF中是Dispatcher.Invoke/BeginInvoke)来委托UI线程执行。 示例代码(在WPF中): private System.Threading.Timer _timer; public MainWindow() { InitializeComponent(); // 创建定时器,每隔1秒触发一次 _timer = new System.Threading.Timer(TimerCallback, null, 0, 1000); } private void TimerCallback(object state) { // 在后台线程执行的操作(非UI操作) // 如果需要更新UI,使用Dispatcher Dispatcher.BeginInvoke(new Action(() => { // 更新UI控件,例如: textBlock.Text = DateTime.Now.ToString(); })); } 销毁定时器:当不再需要定时器时,应该调用Dispose方法释放资源,否则可能导致资源泄漏。通常在窗口关闭事件中处理。 根据引用[3]的提示,我们可以使用锁来保护共享资源的访问,因为多个线程可能同时访问(如果回调执行时间超过间隔,可能会重叠执行)。但注意,在回调方法中尽量避免长时间操作,或者使用锁机制(如lock语句)来避免并发问题。 因此,配置System.Threading.Timer的刷新时间间隔主要是在创建时设置period参数,或者通过Change方法动态调整。 总结步骤: 1. 创建Timer实例,在构造函数中设置dueTime(初始延迟)period(间隔时间)。 2. 如果需要改变间隔,调用Change方法。 3. 在回调方法中,如果需要更新UI,必须使用Dispatcher。 4. 使用完毕后,调用Dispose方法释放。 注意:period参数的单位是毫秒,也可以使用TimeSpan,例如:TimeSpan.FromSeconds(1)表示1秒。 示例(使用TimeSpan): _timer = new Timer(TimerCallback, null, TimeSpan.Zero, TimeSpan.FromSeconds(1)); 这样代码更易读。 另外,如果希望定时器只触发一次,可以将period设置为Timeout.Infinite(或者使用TimeSpan.FromMilliseconds(Timeout.Infinite))。 最后,提醒用户:System.Threading.Timer是轻量级的,适合后台任务,但要注意线程安全资源释放。</think>### 如何配置 System.Threading.Timer 的时间间隔 配置 `System.Threading.Timer` 的时间间隔主要通过其构造函数的 `dueTime` `period` 参数实现,以下是具体方法使用场景: #### 一、核心配置方法 ```csharp // 创建定时器并设置间隔 System.Threading.Timer timer = new System.Threading.Timer( callback: TimerCallback, // 回调方法 state: null, // 传递给回调的参数 dueTime: 2000, // 首次触发延迟(毫秒) period: 1000 // 后续间隔(毫秒) ); // 回调方法定义 private void TimerCallback(object state) { // 在此执行定时任务 Console.WriteLine($"触发时间: {DateTime.Now:HH:mm:ss.fff}"); } ``` #### 二、动态调整间隔(使用 Change 方法) ```csharp // 创建时不立即启动 var timer = new System.Threading.Timer(TimerCallback, null, Timeout.Infinite, Timeout.Infinite); // 启动并设置间隔(首次延迟1秒,后续每500ms触发) timer.Change(dueTime: 1000, period: 500); // 运行中动态调整为2秒间隔 timer.Change(dueTime: 0, period: 2000); // dueTime=0表示立即生效 // 停止定时器 timer.Change(dueTime: Timeout.Infinite, period: Timeout.Infinite); ``` #### 三、关键参数说明 | 参数 | 类型 | 说明 | |-------------|---------|----------------------------------------------------------------------| | **dueTime** | int | 首次触发前的延迟时间(毫秒),0=立即触发,`Timeout.Infinite`=不触发 | | **period** | int | 后续触发间隔(毫秒),`Timeout.Infinite`=单次触发 | | 回调方法 | delegate| 签名:`void MethodName(object state)` | | state对象 | object | 可通过回调的state参数传递数据 | #### 四、使用 TimeSpan 提高可读性 ```csharp // 使用TimeSpan设置间隔(推荐) timer = new System.Threading.Timer( callback: _ => Console.WriteLine("触发"), state: null, dueTime: TimeSpan.FromSeconds(1), // 首次延迟1秒 period: TimeSpan.FromMilliseconds(300) // 后续每300ms触发 ); ``` #### 五、实际应用场景示例 **场景1:高频数据采集(每50ms)** ```csharp var dataTimer = new System.Threading.Timer(_ => { var sensorData = ReadSensor(); // 后台读取传感器 Dispatcher.BeginInvoke(() => UpdateChart(sensorData)); // 安全更新UI }, null, 0, 50); // 立即开始,每50ms执行 ``` **场景2:延迟启动的轮询任务** ```csharp // 10秒后启动,每5分钟执行一次 var dbTimer = new System.Threading.Timer(_ => { CheckDatabaseUpdates(); }, null, TimeSpan.FromSeconds(10), TimeSpan.FromMinutes(5)); ``` #### 六、注意事项 1. **资源释放** 必须显式释放避免内存泄漏: ```csharp timer.Dispose(); // 不再使用时调用 ``` 2. **精度限制** 实际间隔精度受线程池可用性影响,最小间隔建议 ≥ 15ms(Windows系统限制)[^1][^4] 3. **并发控制** 当回调执行时间 > 间隔时会发生重叠执行,需加锁保护: ```csharp private readonly object _lock = new object(); void TimerCallback(object state) { lock (_lock) // 防止并发访问共享资源 { // 临界区代码 } } ``` > ⚠️ **重要提示**:在WPF/WinForms中更新UI时,必须通过`Dispatcher.Invoke`或`Control.Invoke`跨线程操作,否则会引发异常[^2][^5] #### 七、与DispatcherTimer对比 | 特性 | System.Threading.Timer | DispatcherTimer | |--------------------|---------------------------------|-------------------------------| | **最小间隔** | ≈15ms (线程池限制) | ≈50ms (UI消息队列延迟) | | **动态调整** | 支持 (Change方法) | 不支持 (需重建实例) | | **内存开销** | 极低 (无事件订阅) | 较高 (Tick事件绑定) | | **UI线程阻塞** | 不会阻塞 | 会阻塞 | [^1]: System.Threading.Timer通过线程池实现后台定时任务 [^2]: 其回调不在UI线程执行,更新控件需使用Invoke [^3]: 可通过Change方法动态调整间隔 [^4]: 实际精度受线程池调度影响 [^5]: WPF中需使用Dispatcher.BeginInvoke安全更新UI
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值