3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // There are cases where we have multiple assemblies that are going to import this file and
8 // if they are going to also have InternalsVisibleTo between them, there will be a compiler warning
9 // that the type is found both in the source and in a referenced assembly. The compiler will prefer
10 // the version of the type defined in the source
12 // In order to disable the warning for this type we are disabling this warning for this entire file.
13 #pragma warning disable 436
15 // NOTE: This file should not be included in mscorlib. This should only be included in FX libraries that need to provide switches
17 using System.Collections.Generic;
18 using System.Reflection;
19 using System.Runtime.CompilerServices;
20 using System.Threading;
24 internal static partial class LocalAppContext
26 private delegate bool TryGetSwitchDelegate(string switchName, out bool value);
28 private static TryGetSwitchDelegate TryGetSwitchFromCentralAppContext;
29 private static bool s_canForwardCalls;
31 private static Dictionary<string, bool> s_switchMap = new Dictionary<string, bool>();
32 private static readonly object s_syncLock = new object();
34 private static bool DisableCaching { get; set; }
36 static LocalAppContext()
38 // Try to setup the callback into the central AppContext
39 s_canForwardCalls = SetupDelegate();
41 // Populate the default values of the local app context
42 AppContextDefaultValues.PopulateDefaultValues();
44 // Cache the value of the switch that help with testing
45 DisableCaching = IsSwitchEnabled(@"TestSwitch.LocalAppContext.DisableCaching");
48 public static bool IsSwitchEnabled(string switchName)
50 if (s_canForwardCalls)
52 bool isEnabledCentrally;
53 if (TryGetSwitchFromCentralAppContext(switchName, out isEnabledCentrally))
55 // we found the switch, so return whatever value it has
56 return isEnabledCentrally;
58 // if we could not get the value from the central authority, try the local storage.
61 return IsSwitchEnabledLocal(switchName);
64 private static bool IsSwitchEnabledLocal(string switchName)
66 // read the value from the set of local defaults
67 bool isEnabled, isPresent;
70 isPresent = s_switchMap.TryGetValue(switchName, out isEnabled);
73 // If the value is in the set of local switches, reutrn the value
79 // if we could not find the switch name, we should return 'false'
80 // This will preserve the concept of switches been 'off' unless explicitly set to 'on'
84 private static bool SetupDelegate()
86 Type appContextType = typeof(object).Assembly.GetType("System.AppContext");
87 if (appContextType == null)
90 MethodInfo method = appContextType.GetMethod(
91 "TryGetSwitch", // the method name
92 BindingFlags.Static | BindingFlags.Public, // binding flags
93 null, // use the default binder
94 new Type[] { typeof(string), typeof(bool).MakeByRefType() },
95 null); // parameterModifiers - this is ignored by the default binder
99 // Create delegate if we found the method.
100 TryGetSwitchFromCentralAppContext = (TryGetSwitchDelegate)Delegate.CreateDelegate(typeof(TryGetSwitchDelegate), method);
105 [MethodImpl(MethodImplOptions.AggressiveInlining)]
106 internal static bool GetCachedSwitchValue(string switchName, ref int switchValue)
108 if (switchValue < 0) return false;
109 if (switchValue > 0) return true;
111 return GetCachedSwitchValueInternal(switchName, ref switchValue);
114 private static bool GetCachedSwitchValueInternal(string switchName, ref int switchValue)
116 if (LocalAppContext.DisableCaching)
118 return LocalAppContext.IsSwitchEnabled(switchName);
121 bool isEnabled = LocalAppContext.IsSwitchEnabled(switchName);
122 switchValue = isEnabled ? 1 /*true*/ : -1 /*false*/;
127 /// This method is going to be called from the AppContextDefaultValues class when setting up the
128 /// default values for the switches. !!!! This method is called during the static constructor so it does not
129 /// take a lock !!!! If you are planning to use this outside of that, please ensure proper locking.
131 internal static void DefineSwitchDefault(string switchName, bool initialValue)
133 s_switchMap[switchName] = initialValue;
138 #pragma warning restore 436