|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Reflection;
namespace System;
/// <summary>
/// Scope for temporarily setting an <see cref="AppContext"/> switch. Use in a <see langword="using"/> statement.
/// </summary>
/// <remarks>
/// <para>
/// It is recommended to create wrappers for this struct for both simplicity and to allow adding synchronization.
/// See <see cref="BinaryFormatterScope"/> for an example of doing this.
/// </para>
/// </remarks>
public readonly ref struct AppContextSwitchScope
{
private readonly string _switchName;
private readonly bool _originalState;
public AppContextSwitchScope(string switchName, bool enable)
: this(switchName, getDefaultValue: null, enable)
{
}
public AppContextSwitchScope(string switchName, Func<bool>? getDefaultValue, bool enable)
{
if (!AppContext.TryGetSwitch(AppContextSwitchNames.LocalAppContext_DisableCaching, out bool isEnabled)
|| !isEnabled)
{
// It doesn't make sense to try messing with AppContext switches if they are going to be cached.
throw new InvalidOperationException("LocalAppContext switch caching is not disabled.");
}
// AppContext won't have any switch value until it is explicitly set.
if (!AppContext.TryGetSwitch(switchName, out _originalState))
{
_originalState = getDefaultValue is not null && getDefaultValue();
}
AppContext.SetSwitch(switchName, enable);
if (!AppContext.TryGetSwitch(switchName, out isEnabled) || isEnabled != enable)
{
throw new InvalidOperationException($"Could not set {switchName} to {enable}.");
}
_switchName = switchName;
}
public void Dispose()
{
AppContext.SetSwitch(_switchName, _originalState);
if (!AppContext.TryGetSwitch(_switchName, out bool isEnabled) || isEnabled != _originalState)
{
throw new InvalidOperationException($"Could not reset {_switchName} to {_originalState}.");
}
}
/// <summary>
/// Gets the default value for a switch via reflection.
/// </summary>
public static bool GetDefaultValueForSwitchInAssembly(string switchName, string assemblyName, string typeName)
{
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
if (assembly.GetName().Name == assemblyName)
{
Type type = assembly.GetType(typeName)
?? throw new InvalidOperationException($"Could not find {typeName} type in {assemblyName} assembly.");
return type.TestAccessor().Dynamic.GetSwitchDefaultValue(switchName);
}
}
throw new InvalidOperationException($"Could not find {assemblyName} assembly in the test process.");
}
}
|