Xamarin Public Jenkins f3e3aab35a Imported Upstream version 4.3.2.467
Former-commit-id: 9c2cb47f45fa221e661ab616387c9cda183f283d
2016-02-22 11:00:01 -05:00

119 lines
4.0 KiB
C#

// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// <OWNER>[....]</OWNER>
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Security;
namespace System.Threading
{
//
// AsyncLocal<T> represents "ambient" data that is local to a given asynchronous control flow, such as an
// async method. For example, say you want to associate a culture with a given async flow:
//
// static AsyncLocal<Culture> s_currentCulture = new AsyncLocal<Culture>();
//
// static async Task SomeOperationAsync(Culture culture)
// {
// s_currentCulture.Value = culture;
//
// await FooAsync();
// }
//
// static async Task FooAsync()
// {
// PrintStringWithCulture(s_currentCulture.Value);
// }
//
// AsyncLocal<T> also provides optional notifications when the value associated with the current thread
// changes, either because it was explicitly changed by setting the Value property, or implicitly changed
// when the thread encountered an "await" or other context transition. For example, we might want our
// current culture to be communicated to the OS as well:
//
// static AsyncLocal<Culture> s_currentCulture = new AsyncLocal<Culture>(
// args =>
// {
// NativeMethods.SetThreadCulture(args.CurrentValue.LCID);
// });
//
public sealed class AsyncLocal<T> : IAsyncLocal
{
[SecurityCritical] // critical because this action will terminate the process if it throws.
private readonly Action<AsyncLocalValueChangedArgs<T>> m_valueChangedHandler;
//
// Constructs an AsyncLocal<T> that does not receive change notifications.
//
public AsyncLocal()
{
}
//
// Constructs an AsyncLocal<T> with a delegate that is called whenever the current value changes
// on any thread.
//
[SecurityCritical]
public AsyncLocal(Action<AsyncLocalValueChangedArgs<T>> valueChangedHandler)
{
m_valueChangedHandler = valueChangedHandler;
}
public T Value
{
[SecuritySafeCritical]
get
{
object obj = ExecutionContext.GetLocalValue(this);
return (obj == null) ? default(T) : (T)obj;
}
[SecuritySafeCritical]
set
{
ExecutionContext.SetLocalValue(this, value, m_valueChangedHandler != null);
}
}
[SecurityCritical]
void IAsyncLocal.OnValueChanged(object previousValueObj, object currentValueObj, bool contextChanged)
{
Contract.Assert(m_valueChangedHandler != null);
T previousValue = previousValueObj == null ? default(T) : (T)previousValueObj;
T currentValue = currentValueObj == null ? default(T) : (T)currentValueObj;
m_valueChangedHandler(new AsyncLocalValueChangedArgs<T>(previousValue, currentValue, contextChanged));
}
}
//
// Interface to allow non-generic code in ExecutionContext to call into the generic AsyncLocal<T> type.
//
internal interface IAsyncLocal
{
[SecurityCritical]
void OnValueChanged(object previousValue, object currentValue, bool contextChanged);
}
public struct AsyncLocalValueChangedArgs<T>
{
public T PreviousValue { get; private set; }
public T CurrentValue { get; private set; }
//
// If the value changed because we changed to a different ExecutionContext, this is true. If it changed
// because someone set the Value property, this is false.
//
public bool ThreadContextChanged { get; private set; }
internal AsyncLocalValueChangedArgs(T previousValue, T currentValue, bool contextChanged)
: this()
{
PreviousValue = previousValue;
CurrentValue = currentValue;
ThreadContextChanged = contextChanged;
}
}
}