diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Emitter.cs b/src/libraries/Microsoft.Extensions.Options/gen/Emitter.cs
index 1edc429378528..1a547dd45ebbb 100644
--- a/src/libraries/Microsoft.Extensions.Options/gen/Emitter.cs
+++ b/src/libraries/Microsoft.Extensions.Options/gen/Emitter.cs
@@ -382,26 +382,26 @@ public void EmitRangeAttribute(string modifier, string prefix, string className,
string initializationString = emitTimeSpanSupport ?
"""
- if (OperandType == typeof(global::System.TimeSpan))
- {
- if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) ||
- !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum))
- {
- throw new global::System.InvalidOperationException(c_minMaxError);
- }
- Minimum = timeSpanMinimum;
- Maximum = timeSpanMaximum;
- }
- else
- {
- Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError);
- Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError);
- }
+ if (OperandType == typeof(global::System.TimeSpan))
+ {
+ if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) ||
+ !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum))
+ {
+ throw new global::System.InvalidOperationException(MinMaxError);
+ }
+ Minimum = timeSpanMinimum;
+ Maximum = timeSpanMaximum;
+ }
+ else
+ {
+ Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError);
+ Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError);
+ }
"""
:
"""
- Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError);
- Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError);
+ Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError);
+ Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError);
""";
string convertValue = emitTimeSpanSupport ?
@@ -470,7 +470,7 @@ public void EmitRangeAttribute(string modifier, string prefix, string className,
public {{qualifiedClassName}}(global::System.Type type, string minimum, string maximum) : base()
{
OperandType = type;
- NeedToConvertMinMax = true;
+ _needToConvertMinMax = true;
Minimum = minimum;
Maximum = maximum;
}
@@ -483,33 +483,40 @@ public void EmitRangeAttribute(string modifier, string prefix, string className,
public bool ConvertValueInInvariantCulture { get; set; }
public override string FormatErrorMessage(string name) =>
string.Format(global::System.Globalization.CultureInfo.CurrentCulture, GetValidationErrorMessage(), name, Minimum, Maximum);
- private bool NeedToConvertMinMax { get; }
- private bool Initialized { get; set; }
- private const string c_minMaxError = "The minimum and maximum values must be set to valid values.";
+ private readonly bool _needToConvertMinMax;
+ private volatile bool _initialized;
+ private readonly object _lock = new();
+ private const string MinMaxError = "The minimum and maximum values must be set to valid values.";
public override bool IsValid(object? value)
{
- if (!Initialized)
+ if (!_initialized)
{
- if (Minimum is null || Maximum is null)
- {
- throw new global::System.InvalidOperationException(c_minMaxError);
- }
- if (NeedToConvertMinMax)
+ lock (_lock)
{
- System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture;
+ if (!_initialized)
+ {
+ if (Minimum is null || Maximum is null)
+ {
+ throw new global::System.InvalidOperationException(MinMaxError);
+ }
+ if (_needToConvertMinMax)
+ {
+ System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture;
{{initializationString}}
+ }
+ int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum);
+ if (cmp > 0)
+ {
+ throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'.");
+ }
+ else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive))
+ {
+ throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value.");
+ }
+ _initialized = true;
+ }
}
- int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum);
- if (cmp > 0)
- {
- throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'.");
- }
- else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive))
- {
- throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value.");
- }
- Initialized = true;
}
if (value is null or string { Length: 0 })
diff --git a/src/libraries/Microsoft.Extensions.Options/src/Microsoft.Extensions.Options.csproj b/src/libraries/Microsoft.Extensions.Options/src/Microsoft.Extensions.Options.csproj
index de066111eb579..e35606898e391 100644
--- a/src/libraries/Microsoft.Extensions.Options/src/Microsoft.Extensions.Options.csproj
+++ b/src/libraries/Microsoft.Extensions.Options/src/Microsoft.Extensions.Options.csproj
@@ -4,8 +4,8 @@
$(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.1;netstandard2.0;$(NetFrameworkMinimum)
true
true
- false
- 1
+ true
+ 2
Provides a strongly typed way of specifying and accessing settings using dependency injection.
diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/EmitterWithCustomValidator.netcore.g.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/EmitterWithCustomValidator.netcore.g.cs
index 38bacf966df05..b36fff7e49060 100644
--- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/EmitterWithCustomValidator.netcore.g.cs
+++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/EmitterWithCustomValidator.netcore.g.cs
@@ -84,7 +84,7 @@ public __SourceGen__RangeAttribute(double minimum, double maximum) : base()
public __SourceGen__RangeAttribute(global::System.Type type, string minimum, string maximum) : base()
{
OperandType = type;
- NeedToConvertMinMax = true;
+ _needToConvertMinMax = true;
Minimum = minimum;
Maximum = maximum;
}
@@ -97,34 +97,41 @@ public __SourceGen__RangeAttribute(global::System.Type type, string minimum, str
public bool ConvertValueInInvariantCulture { get; set; }
public override string FormatErrorMessage(string name) =>
string.Format(global::System.Globalization.CultureInfo.CurrentCulture, GetValidationErrorMessage(), name, Minimum, Maximum);
- private bool NeedToConvertMinMax { get; }
- private bool Initialized { get; set; }
- private const string c_minMaxError = "The minimum and maximum values must be set to valid values.";
+ private readonly bool _needToConvertMinMax;
+ private volatile bool _initialized;
+ private readonly object _lock = new();
+ private const string MinMaxError = "The minimum and maximum values must be set to valid values.";
public override bool IsValid(object? value)
{
- if (!Initialized)
+ if (!_initialized)
{
- if (Minimum is null || Maximum is null)
+ lock (_lock)
{
- throw new global::System.InvalidOperationException(c_minMaxError);
+ if (!_initialized)
+ {
+ if (Minimum is null || Maximum is null)
+ {
+ throw new global::System.InvalidOperationException(MinMaxError);
+ }
+ if (_needToConvertMinMax)
+ {
+ System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture;
+ Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError);
+ Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError);
+ }
+ int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum);
+ if (cmp > 0)
+ {
+ throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'.");
+ }
+ else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive))
+ {
+ throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value.");
+ }
+ _initialized = true;
+ }
}
- if (NeedToConvertMinMax)
- {
- System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture;
- Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError);
- Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError);
- }
- int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum);
- if (cmp > 0)
- {
- throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'.");
- }
- else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive))
- {
- throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value.");
- }
- Initialized = true;
}
if (value is null or string { Length: 0 })
diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/EmitterWithCustomValidator.netfx.g.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/EmitterWithCustomValidator.netfx.g.cs
index fe77e3e6bd924..1fa2f9c2e2577 100644
--- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/EmitterWithCustomValidator.netfx.g.cs
+++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/EmitterWithCustomValidator.netfx.g.cs
@@ -82,7 +82,7 @@ public __SourceGen__RangeAttribute(double minimum, double maximum) : base()
public __SourceGen__RangeAttribute(global::System.Type type, string minimum, string maximum) : base()
{
OperandType = type;
- NeedToConvertMinMax = true;
+ _needToConvertMinMax = true;
Minimum = minimum;
Maximum = maximum;
}
@@ -95,34 +95,41 @@ public __SourceGen__RangeAttribute(global::System.Type type, string minimum, str
public bool ConvertValueInInvariantCulture { get; set; }
public override string FormatErrorMessage(string name) =>
string.Format(global::System.Globalization.CultureInfo.CurrentCulture, GetValidationErrorMessage(), name, Minimum, Maximum);
- private bool NeedToConvertMinMax { get; }
- private bool Initialized { get; set; }
- private const string c_minMaxError = "The minimum and maximum values must be set to valid values.";
+ private readonly bool _needToConvertMinMax;
+ private volatile bool _initialized;
+ private readonly object _lock = new();
+ private const string MinMaxError = "The minimum and maximum values must be set to valid values.";
public override bool IsValid(object? value)
{
- if (!Initialized)
+ if (!_initialized)
{
- if (Minimum is null || Maximum is null)
+ lock (_lock)
{
- throw new global::System.InvalidOperationException(c_minMaxError);
+ if (!_initialized)
+ {
+ if (Minimum is null || Maximum is null)
+ {
+ throw new global::System.InvalidOperationException(MinMaxError);
+ }
+ if (_needToConvertMinMax)
+ {
+ System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture;
+ Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError);
+ Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError);
+ }
+ int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum);
+ if (cmp > 0)
+ {
+ throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'.");
+ }
+ else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive))
+ {
+ throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value.");
+ }
+ _initialized = true;
+ }
}
- if (NeedToConvertMinMax)
- {
- System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture;
- Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError);
- Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError);
- }
- int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum);
- if (cmp > 0)
- {
- throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'.");
- }
- else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive))
- {
- throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value.");
- }
- Initialized = true;
}
if (value is null or string { Length: 0 })
diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netcore.lang10.g.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netcore.lang10.g.cs
index 7cf1fe61e1a94..789d299cf93c5 100644
--- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netcore.lang10.g.cs
+++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netcore.lang10.g.cs
@@ -410,7 +410,7 @@ public __SourceGen__2C497155_RangeAttribute(double minimum, double maximum) : ba
public __SourceGen__2C497155_RangeAttribute(global::System.Type type, string minimum, string maximum) : base()
{
OperandType = type;
- NeedToConvertMinMax = true;
+ _needToConvertMinMax = true;
Minimum = minimum;
Maximum = maximum;
}
@@ -423,47 +423,54 @@ public __SourceGen__2C497155_RangeAttribute(global::System.Type type, string min
public bool ConvertValueInInvariantCulture { get; set; }
public override string FormatErrorMessage(string name) =>
string.Format(global::System.Globalization.CultureInfo.CurrentCulture, GetValidationErrorMessage(), name, Minimum, Maximum);
- private bool NeedToConvertMinMax { get; }
- private bool Initialized { get; set; }
- private const string c_minMaxError = "The minimum and maximum values must be set to valid values.";
+ private readonly bool _needToConvertMinMax;
+ private volatile bool _initialized;
+ private readonly object _lock = new();
+ private const string MinMaxError = "The minimum and maximum values must be set to valid values.";
public override bool IsValid(object? value)
{
- if (!Initialized)
+ if (!_initialized)
{
- if (Minimum is null || Maximum is null)
+ lock (_lock)
{
- throw new global::System.InvalidOperationException(c_minMaxError);
- }
- if (NeedToConvertMinMax)
- {
- System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture;
- if (OperandType == typeof(global::System.TimeSpan))
+ if (!_initialized)
{
- if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) ||
- !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum))
+ if (Minimum is null || Maximum is null)
{
- throw new global::System.InvalidOperationException(c_minMaxError);
+ throw new global::System.InvalidOperationException(MinMaxError);
}
- Minimum = timeSpanMinimum;
- Maximum = timeSpanMaximum;
- }
- else
- {
- Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError);
- Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError);
+ if (_needToConvertMinMax)
+ {
+ System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture;
+ if (OperandType == typeof(global::System.TimeSpan))
+ {
+ if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) ||
+ !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum))
+ {
+ throw new global::System.InvalidOperationException(MinMaxError);
+ }
+ Minimum = timeSpanMinimum;
+ Maximum = timeSpanMaximum;
+ }
+ else
+ {
+ Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError);
+ Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError);
+ }
+ }
+ int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum);
+ if (cmp > 0)
+ {
+ throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'.");
+ }
+ else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive))
+ {
+ throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value.");
+ }
+ _initialized = true;
}
}
- int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum);
- if (cmp > 0)
- {
- throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'.");
- }
- else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive))
- {
- throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value.");
- }
- Initialized = true;
}
if (value is null or string { Length: 0 })
diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netcore.lang11.g.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netcore.lang11.g.cs
index f7bba04603342..60d511f2e8356 100644
--- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netcore.lang11.g.cs
+++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netcore.lang11.g.cs
@@ -410,7 +410,7 @@ public __SourceGen__RangeAttribute(double minimum, double maximum) : base()
public __SourceGen__RangeAttribute(global::System.Type type, string minimum, string maximum) : base()
{
OperandType = type;
- NeedToConvertMinMax = true;
+ _needToConvertMinMax = true;
Minimum = minimum;
Maximum = maximum;
}
@@ -423,47 +423,54 @@ public __SourceGen__RangeAttribute(global::System.Type type, string minimum, str
public bool ConvertValueInInvariantCulture { get; set; }
public override string FormatErrorMessage(string name) =>
string.Format(global::System.Globalization.CultureInfo.CurrentCulture, GetValidationErrorMessage(), name, Minimum, Maximum);
- private bool NeedToConvertMinMax { get; }
- private bool Initialized { get; set; }
- private const string c_minMaxError = "The minimum and maximum values must be set to valid values.";
+ private readonly bool _needToConvertMinMax;
+ private volatile bool _initialized;
+ private readonly object _lock = new();
+ private const string MinMaxError = "The minimum and maximum values must be set to valid values.";
public override bool IsValid(object? value)
{
- if (!Initialized)
+ if (!_initialized)
{
- if (Minimum is null || Maximum is null)
+ lock (_lock)
{
- throw new global::System.InvalidOperationException(c_minMaxError);
- }
- if (NeedToConvertMinMax)
- {
- System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture;
- if (OperandType == typeof(global::System.TimeSpan))
+ if (!_initialized)
{
- if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) ||
- !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum))
+ if (Minimum is null || Maximum is null)
{
- throw new global::System.InvalidOperationException(c_minMaxError);
+ throw new global::System.InvalidOperationException(MinMaxError);
}
- Minimum = timeSpanMinimum;
- Maximum = timeSpanMaximum;
- }
- else
- {
- Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError);
- Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError);
+ if (_needToConvertMinMax)
+ {
+ System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture;
+ if (OperandType == typeof(global::System.TimeSpan))
+ {
+ if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) ||
+ !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum))
+ {
+ throw new global::System.InvalidOperationException(MinMaxError);
+ }
+ Minimum = timeSpanMinimum;
+ Maximum = timeSpanMaximum;
+ }
+ else
+ {
+ Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError);
+ Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError);
+ }
+ }
+ int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum);
+ if (cmp > 0)
+ {
+ throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'.");
+ }
+ else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive))
+ {
+ throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value.");
+ }
+ _initialized = true;
}
}
- int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum);
- if (cmp > 0)
- {
- throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'.");
- }
- else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive))
- {
- throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value.");
- }
- Initialized = true;
}
if (value is null or string { Length: 0 })
diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netfx.lang10.g.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netfx.lang10.g.cs
index 4b28eb159d147..9c20532b17631 100644
--- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netfx.lang10.g.cs
+++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netfx.lang10.g.cs
@@ -325,7 +325,7 @@ public __SourceGen__2C497155_RangeAttribute(double minimum, double maximum) : ba
public __SourceGen__2C497155_RangeAttribute(global::System.Type type, string minimum, string maximum) : base()
{
OperandType = type;
- NeedToConvertMinMax = true;
+ _needToConvertMinMax = true;
Minimum = minimum;
Maximum = maximum;
}
@@ -338,47 +338,54 @@ public __SourceGen__2C497155_RangeAttribute(global::System.Type type, string min
public bool ConvertValueInInvariantCulture { get; set; }
public override string FormatErrorMessage(string name) =>
string.Format(global::System.Globalization.CultureInfo.CurrentCulture, GetValidationErrorMessage(), name, Minimum, Maximum);
- private bool NeedToConvertMinMax { get; }
- private bool Initialized { get; set; }
- private const string c_minMaxError = "The minimum and maximum values must be set to valid values.";
+ private readonly bool _needToConvertMinMax;
+ private volatile bool _initialized;
+ private readonly object _lock = new();
+ private const string MinMaxError = "The minimum and maximum values must be set to valid values.";
public override bool IsValid(object? value)
{
- if (!Initialized)
+ if (!_initialized)
{
- if (Minimum is null || Maximum is null)
+ lock (_lock)
{
- throw new global::System.InvalidOperationException(c_minMaxError);
- }
- if (NeedToConvertMinMax)
- {
- System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture;
- if (OperandType == typeof(global::System.TimeSpan))
+ if (!_initialized)
{
- if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) ||
- !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum))
+ if (Minimum is null || Maximum is null)
{
- throw new global::System.InvalidOperationException(c_minMaxError);
+ throw new global::System.InvalidOperationException(MinMaxError);
}
- Minimum = timeSpanMinimum;
- Maximum = timeSpanMaximum;
- }
- else
- {
- Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError);
- Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError);
+ if (_needToConvertMinMax)
+ {
+ System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture;
+ if (OperandType == typeof(global::System.TimeSpan))
+ {
+ if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) ||
+ !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum))
+ {
+ throw new global::System.InvalidOperationException(MinMaxError);
+ }
+ Minimum = timeSpanMinimum;
+ Maximum = timeSpanMaximum;
+ }
+ else
+ {
+ Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError);
+ Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError);
+ }
+ }
+ int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum);
+ if (cmp > 0)
+ {
+ throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'.");
+ }
+ else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive))
+ {
+ throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value.");
+ }
+ _initialized = true;
}
}
- int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum);
- if (cmp > 0)
- {
- throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'.");
- }
- else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive))
- {
- throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value.");
- }
- Initialized = true;
}
if (value is null or string { Length: 0 })
diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netfx.lang11.g.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netfx.lang11.g.cs
index 4c300abc6d05b..c563c65e82190 100644
--- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netfx.lang11.g.cs
+++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/GeneratedAttributesTest.netfx.lang11.g.cs
@@ -325,7 +325,7 @@ public __SourceGen__RangeAttribute(double minimum, double maximum) : base()
public __SourceGen__RangeAttribute(global::System.Type type, string minimum, string maximum) : base()
{
OperandType = type;
- NeedToConvertMinMax = true;
+ _needToConvertMinMax = true;
Minimum = minimum;
Maximum = maximum;
}
@@ -338,47 +338,54 @@ public __SourceGen__RangeAttribute(global::System.Type type, string minimum, str
public bool ConvertValueInInvariantCulture { get; set; }
public override string FormatErrorMessage(string name) =>
string.Format(global::System.Globalization.CultureInfo.CurrentCulture, GetValidationErrorMessage(), name, Minimum, Maximum);
- private bool NeedToConvertMinMax { get; }
- private bool Initialized { get; set; }
- private const string c_minMaxError = "The minimum and maximum values must be set to valid values.";
+ private readonly bool _needToConvertMinMax;
+ private volatile bool _initialized;
+ private readonly object _lock = new();
+ private const string MinMaxError = "The minimum and maximum values must be set to valid values.";
public override bool IsValid(object? value)
{
- if (!Initialized)
+ if (!_initialized)
{
- if (Minimum is null || Maximum is null)
+ lock (_lock)
{
- throw new global::System.InvalidOperationException(c_minMaxError);
- }
- if (NeedToConvertMinMax)
- {
- System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture;
- if (OperandType == typeof(global::System.TimeSpan))
+ if (!_initialized)
{
- if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) ||
- !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum))
+ if (Minimum is null || Maximum is null)
{
- throw new global::System.InvalidOperationException(c_minMaxError);
+ throw new global::System.InvalidOperationException(MinMaxError);
}
- Minimum = timeSpanMinimum;
- Maximum = timeSpanMaximum;
- }
- else
- {
- Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError);
- Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError);
+ if (_needToConvertMinMax)
+ {
+ System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture;
+ if (OperandType == typeof(global::System.TimeSpan))
+ {
+ if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) ||
+ !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum))
+ {
+ throw new global::System.InvalidOperationException(MinMaxError);
+ }
+ Minimum = timeSpanMinimum;
+ Maximum = timeSpanMaximum;
+ }
+ else
+ {
+ Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError);
+ Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError);
+ }
+ }
+ int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum);
+ if (cmp > 0)
+ {
+ throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'.");
+ }
+ else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive))
+ {
+ throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value.");
+ }
+ _initialized = true;
}
}
- int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum);
- if (cmp > 0)
- {
- throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'.");
- }
- else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive))
- {
- throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value.");
- }
- Initialized = true;
}
if (value is null or string { Length: 0 })
diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/OptionsRuntimeTests.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/OptionsRuntimeTests.cs
index 4c701e4b9f498..8487570d208b2 100644
--- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/OptionsRuntimeTests.cs
+++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/OptionsRuntimeTests.cs
@@ -7,6 +7,7 @@
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
+using System.Threading;
using System.Threading.Tasks;
using Xunit;
@@ -399,6 +400,23 @@ public void TestCustomGeneratedAttributes()
Assert.Equal(results.Count(), generatorResult.Failures.Count());
}
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+ public void TestGeneratedRangeAttributeThreadSafety()
+ {
+ OptionsWithTimeSpanRangeAttribute options = new OptionsWithTimeSpanRangeAttribute() { Name = "T1", Period = TimeSpan.FromHours(1) };
+ TimeSpanRangeAttributeValidator validator = new TimeSpanRangeAttributeValidator();
+
+ var barrier = new Barrier(8);
+ Task.WaitAll(
+ (from i in Enumerable.Range(0, barrier.ParticipantCount)
+ select Task.Factory.StartNew(() =>
+ {
+ barrier.SignalAndWait();
+ ValidateOptionsResult result = validator.Validate("T1", options);
+ Assert.True(result.Succeeded);
+ }, TaskCreationOptions.LongRunning)).ToArray());
+ }
}
public class FakeCount(int count) { public int Count { get { return count; } } }
@@ -605,4 +623,17 @@ public partial class NewAttributesValidator : IValidateOptions
+ {
+ }
}
diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetCoreApp/Validators.g.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetCoreApp/Validators.g.cs
index 93c101431004c..81a68c3901647 100644
--- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetCoreApp/Validators.g.cs
+++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetCoreApp/Validators.g.cs
@@ -1,4 +1,4 @@
-
+
//
#nullable enable
#pragma warning disable CS1591 // Compensate for https://github.com/dotnet/roslyn/issues/54103
@@ -2195,7 +2195,7 @@ public __SourceGen__RangeAttribute(double minimum, double maximum) : base()
public __SourceGen__RangeAttribute(global::System.Type type, string minimum, string maximum) : base()
{
OperandType = type;
- NeedToConvertMinMax = true;
+ _needToConvertMinMax = true;
Minimum = minimum;
Maximum = maximum;
}
@@ -2208,47 +2208,54 @@ public __SourceGen__RangeAttribute(global::System.Type type, string minimum, str
public bool ConvertValueInInvariantCulture { get; set; }
public override string FormatErrorMessage(string name) =>
string.Format(global::System.Globalization.CultureInfo.CurrentCulture, GetValidationErrorMessage(), name, Minimum, Maximum);
- private bool NeedToConvertMinMax { get; }
- private bool Initialized { get; set; }
- private const string c_minMaxError = "The minimum and maximum values must be set to valid values.";
+ private readonly bool _needToConvertMinMax;
+ private volatile bool _initialized;
+ private readonly object _lock = new();
+ private const string MinMaxError = "The minimum and maximum values must be set to valid values.";
public override bool IsValid(object? value)
{
- if (!Initialized)
+ if (!_initialized)
{
- if (Minimum is null || Maximum is null)
- {
- throw new global::System.InvalidOperationException(c_minMaxError);
- }
- if (NeedToConvertMinMax)
+ lock (_lock)
{
- System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture;
- if (OperandType == typeof(global::System.TimeSpan))
+ if (!_initialized)
{
- if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) ||
- !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum))
+ if (Minimum is null || Maximum is null)
{
- throw new global::System.InvalidOperationException(c_minMaxError);
+ throw new global::System.InvalidOperationException(MinMaxError);
}
- Minimum = timeSpanMinimum;
- Maximum = timeSpanMaximum;
- }
- else
- {
- Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError);
- Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError);
+ if (_needToConvertMinMax)
+ {
+ System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture;
+ if (OperandType == typeof(global::System.TimeSpan))
+ {
+ if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) ||
+ !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum))
+ {
+ throw new global::System.InvalidOperationException(MinMaxError);
+ }
+ Minimum = timeSpanMinimum;
+ Maximum = timeSpanMaximum;
+ }
+ else
+ {
+ Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError);
+ Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError);
+ }
+ }
+ int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum);
+ if (cmp > 0)
+ {
+ throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'.");
+ }
+ else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive))
+ {
+ throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value.");
+ }
+ _initialized = true;
}
}
- int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum);
- if (cmp > 0)
- {
- throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'.");
- }
- else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive))
- {
- throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value.");
- }
- Initialized = true;
}
if (value is null or string { Length: 0 })
diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetFX/Validators.g.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetFX/Validators.g.cs
index 3c9f86fd84f8a..7c388c228a760 100644
--- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetFX/Validators.g.cs
+++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetFX/Validators.g.cs
@@ -1,4 +1,4 @@
-
+
//
#nullable enable
#pragma warning disable CS1591 // Compensate for https://github.com/dotnet/roslyn/issues/54103
@@ -2087,7 +2087,7 @@ public __SourceGen__RangeAttribute(double minimum, double maximum) : base()
public __SourceGen__RangeAttribute(global::System.Type type, string minimum, string maximum) : base()
{
OperandType = type;
- NeedToConvertMinMax = true;
+ _needToConvertMinMax = true;
Minimum = minimum;
Maximum = maximum;
}
@@ -2100,47 +2100,54 @@ public __SourceGen__RangeAttribute(global::System.Type type, string minimum, str
public bool ConvertValueInInvariantCulture { get; set; }
public override string FormatErrorMessage(string name) =>
string.Format(global::System.Globalization.CultureInfo.CurrentCulture, GetValidationErrorMessage(), name, Minimum, Maximum);
- private bool NeedToConvertMinMax { get; }
- private bool Initialized { get; set; }
- private const string c_minMaxError = "The minimum and maximum values must be set to valid values.";
+ private readonly bool _needToConvertMinMax;
+ private volatile bool _initialized;
+ private readonly object _lock = new();
+ private const string MinMaxError = "The minimum and maximum values must be set to valid values.";
public override bool IsValid(object? value)
{
- if (!Initialized)
+ if (!_initialized)
{
- if (Minimum is null || Maximum is null)
- {
- throw new global::System.InvalidOperationException(c_minMaxError);
- }
- if (NeedToConvertMinMax)
+ lock (_lock)
{
- System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture;
- if (OperandType == typeof(global::System.TimeSpan))
+ if (!_initialized)
{
- if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) ||
- !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum))
+ if (Minimum is null || Maximum is null)
{
- throw new global::System.InvalidOperationException(c_minMaxError);
+ throw new global::System.InvalidOperationException(MinMaxError);
}
- Minimum = timeSpanMinimum;
- Maximum = timeSpanMaximum;
- }
- else
- {
- Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError);
- Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError);
+ if (_needToConvertMinMax)
+ {
+ System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture;
+ if (OperandType == typeof(global::System.TimeSpan))
+ {
+ if (!global::System.TimeSpan.TryParse((string)Minimum, culture, out global::System.TimeSpan timeSpanMinimum) ||
+ !global::System.TimeSpan.TryParse((string)Maximum, culture, out global::System.TimeSpan timeSpanMaximum))
+ {
+ throw new global::System.InvalidOperationException(MinMaxError);
+ }
+ Minimum = timeSpanMinimum;
+ Maximum = timeSpanMaximum;
+ }
+ else
+ {
+ Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError);
+ Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(MinMaxError);
+ }
+ }
+ int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum);
+ if (cmp > 0)
+ {
+ throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'.");
+ }
+ else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive))
+ {
+ throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value.");
+ }
+ _initialized = true;
}
}
- int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum);
- if (cmp > 0)
- {
- throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'.");
- }
- else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive))
- {
- throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value.");
- }
- Initialized = true;
}
if (value is null or string { Length: 0 })