C# 线程上下文

    这是一个传参的解决方法:在业务处理线程中设置参数,当前业务线程和之后创建的子线程可以获取参数,而不必修改方法(函数)原型。

0x00 问题

 

0x01 解决

 

    /// <summary>
    /// 线程上下文。
    /// </summary>
    /// <typeparam name="TContext">上下文类型。</typeparam>
    public sealed class ThreadContext<TContext> : MarshalByRefObject 
#if NETFRAMEWORK
        , System.Runtime.Remoting.Messaging.ILogicalThreadAffinative
#endif
        where TContext : class
    {
        /// <summary>
        /// 当前线程上下文。
        /// </summary>
        public static TContext Current
#if NETFRAMEWORK
        {
            [System.Security.SecuritySafeCritical]
            set
            {
                var threadContext = System.Runtime.Remoting.Messaging.CallContext.GetData(currentId) as ThreadContext<TContext>;
                if (threadContext == null)
                {
                    threadContext = new ThreadContext<TContext>();
                    System.Runtime.Remoting.Messaging.CallContext.SetData(currentId, threadContext);
                }
                threadContext.Context = value;
            }
            [System.Security.SecuritySafeCritical]
            get => (System.Runtime.Remoting.Messaging.CallContext.GetData(currentId) as ThreadContext<TContext>)?.Context;
        }
        [DebuggerBrowsable(DebuggerBrowsableState.Never)] static readonly string currentId = $"Orchid.Threading.ThreadContext({typeof(TContext).FullName})";
#else
        {
            set
            {
                if (_currentContext.Value == null) _currentContext.Value = new ThreadContext<TContext>();
                _currentContext.Value.Context = value;
            }
            get => _currentContext.Value?.Context;
        }
        [DebuggerBrowsable(DebuggerBrowsableState.Never)] static readonly System.Threading.AsyncLocal<ThreadContext<TContext>> _currentContext = new System.Threading.AsyncLocal<ThreadContext<TContext>>();
#endif

        [DebuggerBrowsable(DebuggerBrowsableState.Never)] TContext Context { set; get; }

        ThreadContext() { }
    }

 

0x02 测试

 

    using NUnit.Framework;
    using System.Threading.Tasks;

    public class ThreadContextTest
    {
        [Test]
        public void TestMethod()
        {
            var isRunning = false;
            object context = null, context1 = null, context2 = null;

            var task = Task.Run(() =>
            {
                ThreadContext<object>.Current = context = 0;
                Task.Factory.StartNew(() =>
                {
                    context1 = ThreadContext<object>.Current;
                    ThreadContext<object>.Current = 1;
                }).Wait();
                while (!isRunning) System.Threading.Thread.Sleep(200);
            });
            Task.Run(() =>
            {
                ThreadContext<object>.Current = context2 = 2;
                isRunning = true;
            }).Wait();
            task.Wait();

            Assert.NotNull(context);
            Assert.NotNull(context1);
            Assert.NotNull(context2);
            Assert.AreEqual(context, context1);
            Assert.AreNotEqual(context, context2);
        }
    }

 

0x03 总结

 

posted @ 2022-09-09 22:54  青月阁  阅读(121)  评论(0)    收藏  举报