Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / mscorlib / system / threading / asynclocal.cs
blob3e1f5f9f69e6ad429793ecef5a1c3b13373eac5c
1 // ==++==
2 //
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 //
5 // <OWNER>Microsoft</OWNER>
7 using System;
8 using System.Collections.Generic;
9 using System.Diagnostics.Contracts;
10 using System.Security;
12 namespace System.Threading
15 // AsyncLocal<T> represents "ambient" data that is local to a given asynchronous control flow, such as an
16 // async method. For example, say you want to associate a culture with a given async flow:
18 // static AsyncLocal<Culture> s_currentCulture = new AsyncLocal<Culture>();
20 // static async Task SomeOperationAsync(Culture culture)
21 // {
22 // s_currentCulture.Value = culture;
24 // await FooAsync();
25 // }
27 // static async Task FooAsync()
28 // {
29 // PrintStringWithCulture(s_currentCulture.Value);
30 // }
32 // AsyncLocal<T> also provides optional notifications when the value associated with the current thread
33 // changes, either because it was explicitly changed by setting the Value property, or implicitly changed
34 // when the thread encountered an "await" or other context transition. For example, we might want our
35 // current culture to be communicated to the OS as well:
37 // static AsyncLocal<Culture> s_currentCulture = new AsyncLocal<Culture>(
38 // args =>
39 // {
40 // NativeMethods.SetThreadCulture(args.CurrentValue.LCID);
41 // });
43 public sealed class AsyncLocal<T> : IAsyncLocal
45 [SecurityCritical] // critical because this action will terminate the process if it throws.
46 private readonly Action<AsyncLocalValueChangedArgs<T>> m_valueChangedHandler;
49 // Constructs an AsyncLocal<T> that does not receive change notifications.
51 public AsyncLocal()
56 // Constructs an AsyncLocal<T> with a delegate that is called whenever the current value changes
57 // on any thread.
59 [SecurityCritical]
60 public AsyncLocal(Action<AsyncLocalValueChangedArgs<T>> valueChangedHandler)
62 m_valueChangedHandler = valueChangedHandler;
65 public T Value
67 [SecuritySafeCritical]
68 get
70 object obj = ExecutionContext.GetLocalValue(this);
71 return (obj == null) ? default(T) : (T)obj;
73 [SecuritySafeCritical]
74 set
76 ExecutionContext.SetLocalValue(this, value, m_valueChangedHandler != null);
80 [SecurityCritical]
81 void IAsyncLocal.OnValueChanged(object previousValueObj, object currentValueObj, bool contextChanged)
83 Contract.Assert(m_valueChangedHandler != null);
84 T previousValue = previousValueObj == null ? default(T) : (T)previousValueObj;
85 T currentValue = currentValueObj == null ? default(T) : (T)currentValueObj;
86 m_valueChangedHandler(new AsyncLocalValueChangedArgs<T>(previousValue, currentValue, contextChanged));
91 // Interface to allow non-generic code in ExecutionContext to call into the generic AsyncLocal<T> type.
93 internal interface IAsyncLocal
95 [SecurityCritical]
96 void OnValueChanged(object previousValue, object currentValue, bool contextChanged);
99 public struct AsyncLocalValueChangedArgs<T>
101 public T PreviousValue { get; private set; }
102 public T CurrentValue { get; private set; }
105 // If the value changed because we changed to a different ExecutionContext, this is true. If it changed
106 // because someone set the Value property, this is false.
108 public bool ThreadContextChanged { get; private set; }
110 internal AsyncLocalValueChangedArgs(T previousValue, T currentValue, bool contextChanged)
111 : this()
113 PreviousValue = previousValue;
114 CurrentValue = currentValue;
115 ThreadContextChanged = contextChanged;