Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Refactor switches into 'FeatureSwitches' type
  • Loading branch information
Sergio0694 committed Aug 9, 2024
commit 4cad2e085d59173f3fdecf2b6850966f6d3751c2
9 changes: 8 additions & 1 deletion src/CommunityToolkit.Mvvm/ComponentModel/ObservableObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ protected virtual void OnPropertyChanging(PropertyChangingEventArgs e)
{
ArgumentNullException.ThrowIfNull(e);

// When support is disabled, just do nothing
if (!FeatureSwitches.EnableINotifyPropertyChangingSupport)
{
return;
}

PropertyChanging?.Invoke(this, e);
}

Expand All @@ -75,7 +81,8 @@ protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
/// <param name="propertyName">(optional) The name of the property that changed.</param>
protected void OnPropertyChanging([CallerMemberName] string? propertyName = null)
{
if (Configuration.IsINotifyPropertyChangingDisabled)
// When support is disabled, avoid instantiating the event args entirely
if (!FeatureSwitches.EnableINotifyPropertyChangingSupport)
{
return;
}
Expand Down
37 changes: 0 additions & 37 deletions src/CommunityToolkit.Mvvm/Properties/Configuration.cs

This file was deleted.

81 changes: 81 additions & 0 deletions src/CommunityToolkit.Mvvm/Properties/FeatureSwitches.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.Runtime.CompilerServices;

namespace CommunityToolkit.Mvvm;

/// <summary>
/// A container for all shared <see cref="AppContext"/> configuration switches for the MVVM Toolkit.
/// </summary>
/// <remarks>
/// <para>
/// This type uses a very specific setup for configuration switches to ensure ILLink can work the best.
/// This mirrors the architecture of feature switches in the runtime as well, and it's needed so that
/// no static constructor is generated for the type.
/// </para>
/// <para>
/// For more info, see <see href="https://github.com/dotnet/runtime/blob/main/docs/workflow/trimming/feature-switches.md#adding-new-feature-switch"/>.
/// </para>
/// </remarks>
internal static class FeatureSwitches
{
/// <summary>
/// The configuration property name for <see cref="EnableINotifyPropertyChangingSupport"/>.
/// </summary>
private const string EnableINotifyPropertyChangingSupportPropertyName = "MVVMTOOLKIT_ENABLE_INOTIFYPROPERTYCHANGING_SUPPORT";

/// <summary>
/// The backing field for <see cref="EnableINotifyPropertyChangingSupport"/>.
/// </summary>
private static int enableINotifyPropertyChangingSupport;

/// <summary>
/// Gets a value indicating whether or not support for <see cref="System.ComponentModel.INotifyPropertyChanging"/> should be enabled (defaults to <see langword="true"/>).
/// </summary>
public static bool EnableINotifyPropertyChangingSupport
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => GetConfigurationValue(EnableINotifyPropertyChangingSupportPropertyName, ref enableINotifyPropertyChangingSupport, true);
}

/// <summary>
/// Gets a configuration value for a specified property.
/// </summary>
/// <param name="propertyName">The property name to retrieve the value for.</param>
/// <param name="cachedResult">The cached result for the target configuration value.</param>
/// <param name="defaultValue">The default value for the feature switch, if not set.</param>
/// <returns>The value of the specified configuration setting.</returns>
private static bool GetConfigurationValue(string propertyName, ref int cachedResult, bool defaultValue)
{
// The cached switch value has 3 states:
// 0: unknown.
// 1: true
// -1: false
//
// This method doesn't need to worry about concurrent accesses to the cached result,
// as even if the configuration value is retrieved twice, that'll always be the same.
if (cachedResult < 0)
{
return false;
}

if (cachedResult > 0)
{
return true;
}

// Get the configuration switch value, or its default.
// All feature switches have a default set in the .targets file.
if (!AppContext.TryGetSwitch(propertyName, out bool isEnabled))
{
isEnabled = defaultValue;
}

// Update the cached result
cachedResult = isEnabled ? 1 : -1;

return isEnabled;
}
}