这个类库是在codeproject上发现的,主要是用于在.net 2.0,3.5的框架下,不可以在非创建线程下雨控件进行交互的限制,类库封装得比较好,使用了匿名方法。

Code
// Copyright (c) 2008 CodeToast.com and Nicholas Brookins
//This code is free to use in any application for any use if this notice is left intact.
//Just don't sue me if it gets you fired. Enjoy!

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Runtime.Remoting.Messaging;
using System.Threading;
using System.Windows.Forms;


namespace CodeToast
{

public static class Async
{

static Dictionary<string, object> methodLocks = new Dictionary<string, object>();


Async 'Do' overloads, for ease of use#region Async 'Do' overloads, for ease of use

/**//// <summary>
/// Fires off your delegate asyncronously, using the threadpool or a full managed thread if needed.
/// This overload always tries the ThreadPool and DOES NOT check for reentrance.
/// </summary>
/// <param name="d">A delegate with a return value of some sort - can be cast to (DlgR) from an anonymous delgate with a return: Async.Do((DlgR)MyMethod);</param>
/// <param name="getRetVal">If true, and the method/delgete returns something, it is included in the AsyncRes returned (after the method completes)</param>
/// <returns>AsyncRes with all kind o' goodies for waiting, etc.</returns>

public static AsyncRes Do(DlgR d, bool getRetVal)
{
return Do(d, getRetVal, ReenteranceMode.Allow);
}


/**//// <summary>
/// Fires off your delegate asyncronously, using the threadpool or a full managed thread if needed.
/// This overload always tries the ThreadPool and DOES NOT check for reentrance.
/// </summary>
/// <param name="d">A void delegate - can be cast to (Dlg) from an anonymous delgate or method: Async.Do((Dlg)MyVoidMethod)</param>
/// <returns>AsyncRes with all kind o' goodies for waiting, etc.</returns>

public static AsyncRes Do(Dlg d)
{
return Do(d, ReenteranceMode.Allow);
}


/**//// <summary>
/// Fires off your delegate asyncronously, using the threadpool or a full managed thread if needed.
/// </summary>
/// <param name="d">A delegate with a return value of some sort - can be cast to (DlgR) from an anonymous delgate with a return: Async.Do((DlgR)MyMethod);</param>
/// <param name="rMode">If true, will make sure no other instances are running your method.</param>
/// <param name="getRetVal">If true, and the method/delgete returns something, it is included in the AsyncRes returned (after the method completes)</param>
/// <returns>AsyncRes with all kind o' goodies for waiting, resturn and result values, etc.</returns>

public static AsyncRes Do(DlgR d, bool getRetVal, ReenteranceMode rMode)
{
return Do(d, null, getRetVal, null, true, rMode, null, true);
}


/**//// <summary>
/// Fires off your delegate asyncronously, using the threadpool or a full managed thread if needed.
/// </summary>
/// <param name="d">A void delegate - can be cast to (Dlg) from an anonymous delgate or method: Async.Do((Dlg)MyVoidMethod);</param>

/// <param name="rMode">If true, will make sure no other instances are running your method.</param>
/// <returns>AsyncRes with all kind o' goodies for waiting, result values, etc.</returns>

public static AsyncRes Do(Dlg d, ReenteranceMode rMode)
{
return Do(null, d, false, null, true, rMode, null, true);
}


/**//// <summary>
/// Fires off your delegate asyncronously, using the threadpool or a full managed thread if needed.
/// </summary>
/// <param name="d">A delegate with a return value of some sort - can be cast to (DlgR) from an anonymous delgate with a return: Async.Do((DlgR)MyMethod);</param>
/// <param name="state">A user object that can be tracked through the returned result</param>
/// <param name="tryThreadPool">True to use the TP, otherwise just go to a ful lthread - good for long running tasks.</param>
/// <param name="rMode">If true, will make sure no other instances are running your method.</param>
/// <param name="getRetVal">If true, and the method/delgete returns something, it is included in the AsyncRes returned (after the method completes)</param>
/// <returns>AsyncRes with all kind o' goodies for waiting, resturn and result values, etc.</returns>

public static AsyncRes Do(DlgR d, bool getRetVal, object state, bool tryThreadPool, ReenteranceMode rMode)
{
return Do(d, null, getRetVal, state, tryThreadPool, rMode, null, true);
}


/**//// <summary>
/// Fires off your delegate asyncronously, using the threadpool or a full managed thread if needed.
/// </summary>
/// <param name="d">A void delegate - can be cast to (Dlg) from an anonymous delgate or method: Async.Do((Dlg)MyVoidMethod);</param>
/// <param name="state">A user object that can be tracked through the returned result</param>
/// <param name="tryThreadPool">True to use the TP, otherwise just go to a ful lthread - good for long running tasks.</param>
/// <param name="rMode">If true, will make sure no other instances are running your method.</param>
/// <returns>AsyncRes with all kind o' goodies for waiting, result values, etc.</returns>

public static AsyncRes Do(Dlg d, object state, bool tryThreadPool, ReenteranceMode rMode)
{
return Do(null, d, false, state, tryThreadPool, rMode, null, true);
}
#endregion


The Big Main private 'Do' method - called by all overloads.#region The Big Main private 'Do' method - called by all overloads.

/**//// <summary>
/// Fires off your delegate asyncronously, using the threadpool or a full managed thread if needed.
/// </summary>
/// <param name="d">A void delegate - can be cast to (Dlg) from an anonymous delgate.</param>
/// <param name="dr">A delegate with a return value of some sort - can be cast to (DlgR) from an anonymous delgate with a return.</param>
/// <param name="state">A user object that can be tracked through the returned result</param>
/// <param name="getRetVal">If true, and the method/delgete returns something, it is included in the AsyncRes returned (after the method completes)</param>
/// <param name="tryThreadPool">True to use the TP, otherwise just go to a ful lthread - good for long running tasks.</param>
/// <param name="rMode">If true, will make sure no other instances are running your method.</param>
/// <returns>AsyncRes with all kind o' goodies for waiting, result values, etc.</returns>

private static AsyncRes Do(DlgR dr, Dlg d, bool getRetVal, object state, bool tryThreadPool, ReenteranceMode rMode, Control control, bool async)
{
//get a generic MethodInfo for checks..
MethodInfo mi = ((dr != null) ? dr.Method : d.Method);
//make a unique key for output usage
string key = string.Format("{0}{1}{2}{3}", ((getRetVal) ? "<-" : ""), mi.DeclaringType, ((mi.IsStatic) ? ":" : "."), mi.Name);
//our custom return value, holds our delegate, state, key, etc.
AsyncRes res = new AsyncRes(state, ((dr != null) ? (Delegate)dr : (Delegate)d), key, rMode);

//Create a delegate wrapper for what we will actually invoke..

Dlg dlg = (Dlg)delegate
{
if (!BeforeInvoke(res)) return; //checks for reentrance issues and sets us up

try
{
if (res.IsCompleted) return;

if (dr != null)
{
res.retVal = dr();//use this one if theres a return

} else
{
d();//otherwise the simpler dlg
}

} catch (Exception ex)
{ //we never want a rogue exception on a random thread, it can't bubble up anywhere
Console.WriteLine("Async Exception:" + ex);

} finally
{
FinishInvoke(res);//this will fire our callback if they used it, and clean up
}
};


if (control != null)
{
res.control = control;
res.result = AsyncAction.ControlInvoked;

if (!async)
{

if (!control.InvokeRequired)
{
res.completedSynchronously = true;
dlg();

} else
{
control.Invoke(dlg);
}

} else
{
control.BeginInvoke(dlg);
}
return res;
} //don't catch these errors - if this fails, we shouldn't try a real thread or threadpool!


if (tryThreadPool)
{ //we are going to use the .NET threadpool

try
{
//get some stats - much better than trying and silently failing or throwing an expensive exception
int minThreads, minIO, threads, ioThreads, totalThreads, totalIO;
ThreadPool.GetMinThreads(out minThreads, out minIO);
ThreadPool.GetAvailableThreads(out threads, out ioThreads);
ThreadPool.GetMaxThreads(out totalThreads, out totalIO);

//check for at least our thread plus one more in ThreadPool

if (threads > minThreads)
{
//this is what actually fires this task off..

bool result = ThreadPool.QueueUserWorkItem((WaitCallback)delegate
{ dlg(); });

if (result)
{
res.result = AsyncAction.ThreadPool;
//this means success in queueing and running the item
return res;

} else
{
//according to docs, this "won't ever happen" - exception instead, but just for kicks.
Console.WriteLine( "Failed to queue in threadpool.", "Method: " + key);
}

} else
{
Console.WriteLine(String.Format("Insufficient idle threadpool threads: {0} of {1} - min {2}, Method: {3}", threads, totalThreads, minThreads, key));
}

} catch (Exception ex)
{
Console.WriteLine("Failed to queue in threadpool: " + ex.Message, "Method: " + key);
}
}

//if we got this far, then something up there failed, or they wanted a dedicated thread

Thread t = new Thread((ThreadStart)delegate
{ dlg(); });
t.IsBackground = true; //this or threadpriority are candidates for additional settings
t.Name = "Async_" + key;
res.result = AsyncAction.Thread;
t.Start();

return res;
}
#endregion


Before and after - helper methods#region Before and after - helper methods


private static bool BeforeInvoke(AsyncRes res)
{
//if marked as completed then we abort.
if (res.IsCompleted) return false;
//if mode is 'allow' there is nothing to check. Otherwise

if (res.RMode != ReenteranceMode.Allow)
{
//be threadsafe with our one and only member field

lock (methodLocks)
{

if (!methodLocks.ContainsKey(res.Method))
{
//make sure we have a generic locking object in the collection, it will already be there if we are reentering
methodLocks.Add(res.Method, new object());
}
//if bypass mode and we can't get or lock, we dump out.

if (res.RMode == ReenteranceMode.Bypass)
{

if (!Monitor.TryEnter(methodLocks[res.Method]))
{
res.result = AsyncAction.Reenterant;
return false;
}

} else
{
//Otherwise in 'stack' mode, we just wait until someone else releases it
Monitor.Enter(methodLocks[res.Method]);
}

//if we are here, all is good.
//Set some properties on the result class to show when we started, and what thread we are on
res.isStarted = true;
res.startTime = DateTime.Now;
res.thread = Thread.CurrentThread;
}
}

return true;
}


private static void FinishInvoke(AsyncRes res)
{
if (res == null) return;

try
{
//finish a few more properties
res.isCompleted = true;
res.completeTime = DateTime.Now;
//set the resetevent, in case someone is using the waithandle to know when we have completed.
res.mre.Set();

} catch (Exception ex)
{
Console.WriteLine("Error setting wait handle on " + (res.Method ?? "NULL") + ex);
}


if (res.RMode != ReenteranceMode.Allow)
{
//if mode is bypass or stack, then we must have a lock that needs releasing

try
{

if (methodLocks.ContainsKey(res.Method))
{
Monitor.Exit(methodLocks[res.Method]);
}

} catch (Exception ex)
{
Console.WriteLine("Error releasing reentrant lock on " + (res.Method ?? "NULL")+ ex);
}
}
}

#endregion


UI Overloads#region UI Overloads

/**//// <summary>
/// Fires off your delegate, carefully using the correct UI thread
/// </summary>
/// <param name="d">A void delegate - can be cast to (Dlg) from an anonymous delgate or method: Async.Do((Dlg)MyVoidMethod);</param>
/// <param name="async">Whether to run async, or try on current thread if invoke is not required.</param>
/// <param name="c">A control to Invoke upon GUI thread of, if needed. Null if unused.</param>
/// <returns>AsyncRes with all kind o' goodies for waiting, result values, etc.</returns>

public static AsyncRes UI(Dlg d, Control c, bool async)
{
return Do(null, d, false, null, false, ReenteranceMode.Allow, c, async);
}


/**//// <summary>
/// Fires off your delegate, carefully using the correct UI thread
/// </summary>
/// <param name="d">A delegate with a return value of some sort - can be cast to (DlgR) from an anonymous delgate with a return: Async.Do((DlgR)MyMethod);</param>
/// <param name="async">Whether to run async, or try on current thread if invoke is not required.</param>
/// <param name="getRetVal">If true, and the method/delgete returns something, it is included in the AsyncRes returned (after the method completes)</param>
/// <param name="c">A control to Invoke upon GUI thread of, if needed. Null if unused.</param>
/// <returns>AsyncRes with all kind o' goodies for waiting, result values, etc.</returns>

public static AsyncRes UI(DlgR d, bool getRetVal, Control c, bool async)
{
return Do(d, null, getRetVal, null, false, ReenteranceMode.Allow, c, async);
}


/**//// <summary>
/// Fires off your delegate, carefully using the correct UI thread
/// </summary>
/// <param name="d">A delegate with a return value of some sort - can be cast to (DlgR) from an anonymous delgate with a return: Async.Do((DlgR)MyMethod);</param>
/// <param name="state">A user object that can be tracked through the returned result</param>
/// <param name="async">Whether to run async, or try on current thread if invoke is not required.</param>
/// <param name="getRetVal">If true, and the method/delgete returns something, it is included in the AsyncRes returned (after the method completes)</param>
/// <param name="rMode">If true, will make sure no other instances are running your method.</param>
/// <param name="c">A control to Invoke upon GUI thread of, if needed. Null if unused.</param>
/// <returns>AsyncRes with all kind o' goodies for waiting, result values, etc.</returns>

public static AsyncRes UI(DlgR d, bool getRetVal, Control c, object state, bool async, ReenteranceMode rMode)
{
return Do(d, null, getRetVal, state, false, rMode, c, async);
}
#endregion
}


AsyncRes class#region AsyncRes class

/**//// <summary>
/// Used with the Async helper class, This class is mostly a holder for a lot of tracking fields and properties, with a few things mandated by the IAsyncResult interface.
/// </summary>

public class AsyncRes : IAsyncResult
{


internal AsyncRes(object state, Delegate d, string key, ReenteranceMode rMode)
{
this.state = state;
this.asyncDelegate = d;
this.key = key;
this.RMode = rMode;
}

internal ReenteranceMode RMode = ReenteranceMode.Allow;

internal Thread thread = null;

private string key = null;

public string Method
{ get
{ return key; } }

private Delegate asyncDelegate = null;

public Delegate AsyncDelegate
{ get
{ return asyncDelegate; } }

internal AsyncAction result = AsyncAction.Unknown;

public AsyncAction Result
{ get
{ return result; } }

internal Control control = null;

public Control Control
{ get
{ return control; } }

internal DateTime createTime = DateTime.Now;

public DateTime TimeCreated
{ get
{ return createTime; } }

internal DateTime completeTime = DateTime.MinValue;

public DateTime TimeCompleted
{ get
{ return completeTime; } }

internal DateTime startTime = DateTime.Now;

public DateTime TimeStarted
{ get
{ return startTime; } }


public TimeSpan TimeElapsed
{

get
{ return ((completeTime > DateTime.MinValue) ? completeTime : DateTime.Now) - createTime; }
}


public TimeSpan TimeRunning
{

get
{return (startTime == DateTime.MinValue) ? TimeSpan.Zero : ((completeTime > DateTime.MinValue) ? completeTime : DateTime.Now) - startTime;}
}

internal object retVal = null;

public object ReturnValue
{ get
{ return retVal; } }

internal bool isStarted = false;

public bool IsStarted
{ get
{ return isStarted; } }

private object state = null;

public object AsyncState
{ get
{ return state; } }


/**//// <summary>
/// Aborts a running associated thread. If possible it will cancel if not yet started
/// </summary>
/// <returns>True if the thread could be cancelled before it started.</returns>

public bool CancelOrAbort()
{
isCompleted = true;
if (!isStarted) return true;//cancelled


if (thread != null && thread.IsAlive)
{
thread.Abort();
}

return false;
}

internal ManualResetEvent mre = new ManualResetEvent(false);

public WaitHandle AsyncWaitHandle
{ get
{ return mre; } }

internal bool completedSynchronously = false;

public bool CompletedSynchronously
{ get
{ return completedSynchronously; } }

internal bool isCompleted = false;

public bool IsCompleted
{ get
{ return isCompleted; } }
}
#endregion


Definitions of enums and delegates#region Definitions of enums and delegates


/**//// <summary>
/// Abreviated Empty Delegate for use in anonymous casting
/// </summary>
public delegate void Dlg();


/**//// <summary>
/// Abreviated Empty Delegate for use in anonymous methods when a return is needed
/// </summary>
/// <returns>Umm, anything you want.</returns>
public delegate object DlgR();


public enum AsyncAction
{
Unknown = 0,
ThreadPool = 1,
Thread = 2,
Failed = 4,
Reenterant = 8,
ControlInvoked = 16
}


public enum ReenteranceMode
{
Allow = 1,
Bypass = 2,
Stack = 4,
}
#endregion
}

异步获取控件值:

Code
AsyncRes result = Async.UI(
//make sure the delegate/method returns a value:

delegate
{ return textBox1.Text; },
true, //yes, we want to get the return value
myForm, //the control to invoke on
null, //the state object, we don't need to track anything.
true, //invoke asynchronously?
ReenteranceMode.Allow); //don't worry about thread safety in this case.

//
. do other things
//

// now make sure the task above has completed..
result.AsyncWaitHandle.WaitOne();

//and use the value
Console.WriteLine("The textbox says: " + result.ReturnValue);


同步设置控件值:

Code
Async.UI(delegate { textBox1.Text = "This is way easier!"; }, textBox1, true);
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?