File: AppContextSwitchScope.cs
Web Access
Project: src\src\Common\tests\TestUtilities\System.Private.Windows.Core.TestUtilities.csproj (System.Private.Windows.Core.TestUtilities)
// 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.");
    }
}