FeatureSwitches.cs 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. using System;
  5. using System.Runtime.CompilerServices;
  6. namespace CommunityToolkit.Mvvm;
  7. /// <summary>
  8. /// A container for all shared <see cref="AppContext"/> configuration switches for the MVVM Toolkit.
  9. /// </summary>
  10. /// <remarks>
  11. /// <para>
  12. /// This type uses a very specific setup for configuration switches to ensure ILLink can work the best.
  13. /// This mirrors the architecture of feature switches in the runtime as well, and it's needed so that
  14. /// no static constructor is generated for the type.
  15. /// </para>
  16. /// <para>
  17. /// For more info, see <see href="https://github.com/dotnet/runtime/blob/main/docs/workflow/trimming/feature-switches.md#adding-new-feature-switch"/>.
  18. /// </para>
  19. /// </remarks>
  20. internal static class FeatureSwitches
  21. {
  22. /// <summary>
  23. /// The configuration property name for <see cref="EnableINotifyPropertyChangingSupport"/>.
  24. /// </summary>
  25. private const string EnableINotifyPropertyChangingSupportPropertyName = "MVVMTOOLKIT_ENABLE_INOTIFYPROPERTYCHANGING_SUPPORT";
  26. /// <summary>
  27. /// The backing field for <see cref="EnableINotifyPropertyChangingSupport"/>.
  28. /// </summary>
  29. private static int enableINotifyPropertyChangingSupport;
  30. /// <summary>
  31. /// Gets a value indicating whether or not support for <see cref="System.ComponentModel.INotifyPropertyChanging"/> should be enabled (defaults to <see langword="true"/>).
  32. /// </summary>
  33. public static bool EnableINotifyPropertyChangingSupport
  34. {
  35. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  36. get => GetConfigurationValue(EnableINotifyPropertyChangingSupportPropertyName, ref enableINotifyPropertyChangingSupport, true);
  37. }
  38. /// <summary>
  39. /// Gets a configuration value for a specified property.
  40. /// </summary>
  41. /// <param name="propertyName">The property name to retrieve the value for.</param>
  42. /// <param name="cachedResult">The cached result for the target configuration value.</param>
  43. /// <param name="defaultValue">The default value for the feature switch, if not set.</param>
  44. /// <returns>The value of the specified configuration setting.</returns>
  45. private static bool GetConfigurationValue(string propertyName, ref int cachedResult, bool defaultValue)
  46. {
  47. // The cached switch value has 3 states:
  48. // 0: unknown.
  49. // 1: true
  50. // -1: false
  51. //
  52. // This method doesn't need to worry about concurrent accesses to the cached result,
  53. // as even if the configuration value is retrieved twice, that'll always be the same.
  54. if (cachedResult < 0)
  55. {
  56. return false;
  57. }
  58. if (cachedResult > 0)
  59. {
  60. return true;
  61. }
  62. // Get the configuration switch value, or its default.
  63. // All feature switches have a default set in the .targets file.
  64. if (!AppContext.TryGetSwitch(propertyName, out bool isEnabled))
  65. {
  66. isEnabled = defaultValue;
  67. }
  68. // Update the cached result
  69. cachedResult = isEnabled ? 1 : -1;
  70. return isEnabled;
  71. }
  72. }