internal static void SetLocalValue(IAsyncLocal local, object newValue, bool needChangeNotifications) { ExecutionContext current = t_currentMaybeNull ?? ExecutionContext.Default; object previousValue; bool hadPreviousValue = current.m_localValues.TryGetValue(local, out previousValue); if (previousValue == newValue) { return; } current = new ExecutionContext(current); current.m_localValues[local] = newValue; t_currentMaybeNull = current; if (needChangeNotifications) { if (hadPreviousValue) { Debug.Assert(current.m_localChangeNotifications.Contains(local)); } else { current.m_localChangeNotifications.Add(local); } local.OnValueChanged(previousValue, newValue, false); } }
internal static void SetLocalValue(IAsyncLocal local, object newValue, bool needChangeNotifications) { ExecutionContext mutableExecutionContext = Thread.CurrentThread.GetMutableExecutionContext(); object obj = null; bool flag = mutableExecutionContext._localValues != null && mutableExecutionContext._localValues.TryGetValue(local, out obj); if (obj == newValue) { return; } IAsyncLocalValueMap asyncLocalValueMap = mutableExecutionContext._localValues; if (asyncLocalValueMap == null) { asyncLocalValueMap = AsyncLocalValueMap.Create(local, newValue, !needChangeNotifications); } else { asyncLocalValueMap = asyncLocalValueMap.Set(local, newValue, !needChangeNotifications); } mutableExecutionContext._localValues = asyncLocalValueMap; if (needChangeNotifications) { if (!flag) { IAsyncLocal[] array = mutableExecutionContext._localChangeNotifications; if (array == null) { array = new IAsyncLocal[] { local }; } else { int num = array.Length; Array.Resize <IAsyncLocal>(ref array, num + 1); array[num] = local; } mutableExecutionContext._localChangeNotifications = array; } local.OnValueChanged(obj, newValue, false); } }
internal static void SetLocalValue(IAsyncLocal local, object newValue, bool needChangeNotifications) { ExecutionContext executionContext1 = Thread.CurrentThread.GetMutableExecutionContext(); object previousValue = (object)null; bool flag = executionContext1._localValues != null && executionContext1._localValues.TryGetValue(local, out previousValue); if (previousValue == newValue) { return; } if (executionContext1._localValues == null) { executionContext1._localValues = new Dictionary <IAsyncLocal, object>(); } else { ExecutionContext executionContext2 = executionContext1; Dictionary <IAsyncLocal, object> dictionary = new Dictionary <IAsyncLocal, object>((IDictionary <IAsyncLocal, object>)executionContext2._localValues); executionContext2._localValues = dictionary; } executionContext1._localValues[local] = newValue; if (!needChangeNotifications) { return; } if (!flag) { if (executionContext1._localChangeNotifications == null) { executionContext1._localChangeNotifications = new List <IAsyncLocal>(); } else { ExecutionContext executionContext2 = executionContext1; List <IAsyncLocal> asyncLocalList = new List <IAsyncLocal>((IEnumerable <IAsyncLocal>)executionContext2._localChangeNotifications); executionContext2._localChangeNotifications = asyncLocalList; } executionContext1._localChangeNotifications.Add(local); } local.OnValueChanged(previousValue, newValue, false); }
internal static void SetLocalValue(IAsyncLocal local, object newValue, bool needChangeNotifications) { ExecutionContext current = Thread.CurrentThread.ExecutionContext ?? ExecutionContext.Default; object previousValue; bool hadPreviousValue = current.m_localValues.TryGetValue(local, out previousValue); if (previousValue == newValue) { return; } IAsyncLocalValueMap newValues = current.m_localValues.Set(local, newValue); // // Either copy the change notification array, or create a new one, depending on whether we need to add a new item. // IAsyncLocal[] newChangeNotifications = current.m_localChangeNotifications; if (needChangeNotifications) { if (hadPreviousValue) { Contract.Assert(Array.IndexOf(newChangeNotifications, local) >= 0); } else { int newNotificationIndex = newChangeNotifications.Length; Array.Resize(ref newChangeNotifications, newNotificationIndex + 1); newChangeNotifications[newNotificationIndex] = local; } } Thread.CurrentThread.ExecutionContext = new ExecutionContext(newValues, newChangeNotifications, current.m_isFlowSuppressed); if (needChangeNotifications) { local.OnValueChanged(previousValue, newValue, false); } }
internal static void SetLocalValue(IAsyncLocal local, object newValue, bool needChangeNotifications) { ExecutionContext current = Thread.CurrentThread.ExecutionContext ?? ExecutionContext.Default; object previousValue; bool hadPreviousValue = current.m_localValues.TryGetValue(local, out previousValue); if (previousValue == newValue) return; IAsyncLocalValueMap newValues = current.m_localValues.Set(local, newValue); // // Either copy the change notification array, or create a new one, depending on whether we need to add a new item. // IAsyncLocal[] newChangeNotifications = current.m_localChangeNotifications; if (needChangeNotifications) { if (hadPreviousValue) { Contract.Assert(Array.IndexOf(newChangeNotifications, local) >= 0); } else { int newNotificationIndex = newChangeNotifications.Length; Array.Resize(ref newChangeNotifications, newNotificationIndex + 1); newChangeNotifications[newNotificationIndex] = local; } } Thread.CurrentThread.ExecutionContext = new ExecutionContext(newValues, newChangeNotifications, current.m_isFlowSuppressed); if (needChangeNotifications) { local.OnValueChanged(previousValue, newValue, false); } }
internal static void SetLocalValue(IAsyncLocal local, object newValue, bool needChangeNotifications) { ExecutionContext current = t_currentMaybeNull ?? ExecutionContext.Default; object previousValue; bool hadPreviousValue = current.m_localValues.TryGetValue(local, out previousValue); if (previousValue == newValue) return; current = new ExecutionContext(current); current.m_localValues[local] = newValue; t_currentMaybeNull = current; if (needChangeNotifications) { if (hadPreviousValue) Contract.Assert(current.m_localChangeNotifications.Contains(local)); else current.m_localChangeNotifications.Add(local); local.OnValueChanged(previousValue, newValue, false); } }
internal static void SetLocalValue(IAsyncLocal local, object newValue, bool needChangeNotifications) { ExecutionContext current = Thread.CurrentThread.ExecutionContext ?? ExecutionContext.Default; object previousValue; bool hadPreviousValue = current.m_localValues.TryGetValue(local, out previousValue); if (previousValue == newValue) return; // // Allocate a new Dictionary containing a copy of the old values, plus the new value. We have to do this manually to // minimize allocations of IEnumerators, etc. // Dictionary<IAsyncLocal, object> newValues = new Dictionary<IAsyncLocal, object>(current.m_localValues.Count + (hadPreviousValue ? 0 : 1)); foreach (KeyValuePair<IAsyncLocal, object> pair in current.m_localValues) newValues.Add(pair.Key, pair.Value); newValues[local] = newValue; // // Either copy the change notification array, or create a new one, depending on whether we need to add a new item. // IAsyncLocal[] newChangeNotifications = current.m_localChangeNotifications; if (needChangeNotifications) { if (hadPreviousValue) { Contract.Assert(Array.IndexOf(newChangeNotifications, local) >= 0); } else { int newNotificationIndex = newChangeNotifications.Length; Array.Resize(ref newChangeNotifications, newNotificationIndex + 1); newChangeNotifications[newNotificationIndex] = local; } } Thread.CurrentThread.ExecutionContext = new ExecutionContext(newValues, newChangeNotifications, current.m_isFlowSuppressed); if (needChangeNotifications) { local.OnValueChanged(previousValue, newValue, false); } }
internal static void SetLocalValue(IAsyncLocal local, object newValue, bool needChangeNotifications) { ExecutionContext current = Thread.CurrentThread.ExecutionContext; object previousValue = null; bool hadPreviousValue = false; if (current != null) { hadPreviousValue = current.m_localValues.TryGetValue(local, out previousValue); } if (previousValue == newValue) { return; } IAsyncLocal[] newChangeNotifications = null; IAsyncLocalValueMap newValues; bool isFlowSuppressed = false; if (current != null) { isFlowSuppressed = current.m_isFlowSuppressed; newValues = current.m_localValues.Set(local, newValue); newChangeNotifications = current.m_localChangeNotifications; } else { // First AsyncLocal newValues = new AsyncLocalValueMap.OneElementAsyncLocalValueMap(local, newValue); } // // Either copy the change notification array, or create a new one, depending on whether we need to add a new item. // if (needChangeNotifications) { if (hadPreviousValue) { Debug.Assert(newChangeNotifications != null); Debug.Assert(Array.IndexOf(newChangeNotifications, local) >= 0); } else if (newChangeNotifications == null) { newChangeNotifications = new IAsyncLocal[1] { local }; } else { int newNotificationIndex = newChangeNotifications.Length; Array.Resize(ref newChangeNotifications, newNotificationIndex + 1); newChangeNotifications[newNotificationIndex] = local; } } Thread.CurrentThread.ExecutionContext = (!isFlowSuppressed && newValues.GetType() == typeof(AsyncLocalValueMap.EmptyAsyncLocalValueMap)) ? null : // No values, return to Default context new ExecutionContext(newValues, newChangeNotifications, isFlowSuppressed); if (needChangeNotifications) { local.OnValueChanged(previousValue, newValue, contextChanged: false); } }
internal static void SetLocalValue(IAsyncLocal local, object newValue, bool needChangeNotifications) { ExecutionContext current = Thread.CurrentThread.ExecutionContext; object previousValue = null; bool hadPreviousValue = false; if (current != null) { hadPreviousValue = current.m_localValues.TryGetValue(local, out previousValue); } if (previousValue == newValue) { return; } // Regarding 'treatNullValueAsNonexistent: !needChangeNotifications' below: // - When change notifications are not necessary for this IAsyncLocal, there is no observable difference between // storing a null value and removing the IAsyncLocal from 'm_localValues' // - When change notifications are necessary for this IAsyncLocal, the IAsyncLocal's absence in 'm_localValues' // indicates that this is the first value change for the IAsyncLocal and it needs to be registered for change // notifications. So in this case, a null value must be stored in 'm_localValues' to indicate that the IAsyncLocal // is already registered for change notifications. IAsyncLocal[] newChangeNotifications = null; IAsyncLocalValueMap newValues; bool isFlowSuppressed = false; if (current != null) { isFlowSuppressed = current.m_isFlowSuppressed; newValues = current.m_localValues.Set(local, newValue, treatNullValueAsNonexistent: !needChangeNotifications); newChangeNotifications = current.m_localChangeNotifications; } else { // First AsyncLocal newValues = AsyncLocalValueMap.Create(local, newValue, treatNullValueAsNonexistent: !needChangeNotifications); } // // Either copy the change notification array, or create a new one, depending on whether we need to add a new item. // if (needChangeNotifications) { if (hadPreviousValue) { Debug.Assert(newChangeNotifications != null); Debug.Assert(Array.IndexOf(newChangeNotifications, local) >= 0); } else if (newChangeNotifications == null) { newChangeNotifications = new IAsyncLocal[1] { local }; } else { int newNotificationIndex = newChangeNotifications.Length; Array.Resize(ref newChangeNotifications, newNotificationIndex + 1); newChangeNotifications[newNotificationIndex] = local; } } Thread.CurrentThread.ExecutionContext = (!isFlowSuppressed && AsyncLocalValueMap.IsEmpty(newValues)) ? null : // No values, return to Default context new ExecutionContext(newValues, newChangeNotifications, isFlowSuppressed); if (needChangeNotifications) { local.OnValueChanged(previousValue, newValue, contextChanged: false); } }