Skip to content

Commit 4cad2e0

Browse files
committed
Refactor switches into 'FeatureSwitches' type
1 parent af55190 commit 4cad2e0

File tree

3 files changed

+89
-38
lines changed

3 files changed

+89
-38
lines changed

src/CommunityToolkit.Mvvm/ComponentModel/ObservableObject.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ protected virtual void OnPropertyChanging(PropertyChangingEventArgs e)
5757
{
5858
ArgumentNullException.ThrowIfNull(e);
5959

60+
// When support is disabled, just do nothing
61+
if (!FeatureSwitches.EnableINotifyPropertyChangingSupport)
62+
{
63+
return;
64+
}
65+
6066
PropertyChanging?.Invoke(this, e);
6167
}
6268

@@ -75,7 +81,8 @@ protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
7581
/// <param name="propertyName">(optional) The name of the property that changed.</param>
7682
protected void OnPropertyChanging([CallerMemberName] string? propertyName = null)
7783
{
78-
if (Configuration.IsINotifyPropertyChangingDisabled)
84+
// When support is disabled, avoid instantiating the event args entirely
85+
if (!FeatureSwitches.EnableINotifyPropertyChangingSupport)
7986
{
8087
return;
8188
}

src/CommunityToolkit.Mvvm/Properties/Configuration.cs

Lines changed: 0 additions & 37 deletions
This file was deleted.
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
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

Comments
 (0)