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