diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/KeySplineConverter.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/KeySplineConverter.cs index d167bc0e271..f452645decc 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/KeySplineConverter.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/KeySplineConverter.cs @@ -1,17 +1,18 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using MS.Internal; -using System.ComponentModel; using System.ComponentModel.Design.Serialization; +using System.Runtime.CompilerServices; +using System.Windows.Media.Animation; +using System.ComponentModel; using System.Globalization; using System.Reflection; -using System.Windows.Media.Animation; +using MS.Internal; namespace System.Windows { /// - /// PointConverter - Converter class for converting instances of other types to Point instances + /// Converter class for converting instances of to and vice versa. /// /// public class KeySplineConverter : TypeConverter @@ -19,17 +20,14 @@ public class KeySplineConverter : TypeConverter /// /// CanConvertFrom - Returns whether or not this class can convert from a given type /// - /// + /// + /// if the given can be converted from, otherwise. + /// + /// The for this call. + /// The being queried for support. public override bool CanConvertFrom(ITypeDescriptorContext typeDescriptor, Type destinationType) { - if (destinationType == typeof(string)) - { - return true; - } - else - { - return false; - } + return destinationType == typeof(string); } /// @@ -37,93 +35,91 @@ public override bool CanConvertFrom(ITypeDescriptorContext typeDescriptor, Type /// /// ITypeDescriptorContext /// Type to convert to - /// true if conversion is possible - /// + /// + /// if this class can convert to , otherwise. + /// public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { - if ( destinationType == typeof(InstanceDescriptor) - || destinationType == typeof(string)) - { - return true; - } - else - { - return false; - } + return destinationType == typeof(InstanceDescriptor) || destinationType == typeof(string); } /// - /// ConvertFrom + /// Converts of type to its represensation. /// - public override object ConvertFrom( - ITypeDescriptorContext context, - CultureInfo cultureInfo, - object value) + /// The for this call. + /// The which is respected during conversion. + /// The object to convert to a . + /// A new instance of class representing the data contained in . + /// Thrown in case the was not a . + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo cultureInfo, object value) { - string stringValue = value as string; - - if (value == null) - { + if (value is not string stringValue) throw new NotSupportedException(SR.Converter_ConvertFromNotSupported); - } - TokenizerHelper th = new TokenizerHelper(stringValue, cultureInfo); + ValueTokenizerHelper tokenizer = new(stringValue, cultureInfo); return new KeySpline( - Convert.ToDouble(th.NextTokenRequired(), cultureInfo), - Convert.ToDouble(th.NextTokenRequired(), cultureInfo), - Convert.ToDouble(th.NextTokenRequired(), cultureInfo), - Convert.ToDouble(th.NextTokenRequired(), cultureInfo)); + double.Parse(tokenizer.NextTokenRequired(), cultureInfo), + double.Parse(tokenizer.NextTokenRequired(), cultureInfo), + double.Parse(tokenizer.NextTokenRequired(), cultureInfo), + double.Parse(tokenizer.NextTokenRequired(), cultureInfo)); } /// - /// TypeConverter method implementation. + /// Attempt to convert a class to the . /// /// ITypeDescriptorContext /// current culture (see CLR specs), null is a valid value /// value to convert from /// Type to convert to - /// converted value - /// - public override object ConvertTo( - ITypeDescriptorContext context, - CultureInfo cultureInfo, - object value, - Type destinationType) + /// + /// The formatted as using the specified or an . + /// + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo cultureInfo, object value, Type destinationType) { - KeySpline keySpline = value as KeySpline; - - if (keySpline != null && destinationType != null) + if (value is KeySpline keySpline && destinationType is not null) { - if (destinationType == typeof(InstanceDescriptor)) - { - ConstructorInfo ci = typeof(KeySpline).GetConstructor(new Type[] - { - typeof(double), typeof(double), - typeof(double), typeof(double) - }); + if (destinationType == typeof(string)) + return ToString(keySpline, cultureInfo); - return new InstanceDescriptor(ci, new object[] - { - keySpline.ControlPoint1.X, keySpline.ControlPoint1.Y, - keySpline.ControlPoint2.X, keySpline.ControlPoint2.Y - }); - } - else if (destinationType == typeof(string)) + if (destinationType == typeof(InstanceDescriptor)) { - return String.Format( - cultureInfo, - "{0}{4}{1}{4}{2}{4}{3}", - keySpline.ControlPoint1.X, - keySpline.ControlPoint1.Y, - keySpline.ControlPoint2.X, - keySpline.ControlPoint2.Y, - cultureInfo != null ? cultureInfo.TextInfo.ListSeparator : CultureInfo.InvariantCulture.TextInfo.ListSeparator); + ConstructorInfo ci = typeof(KeySpline).GetConstructor(new Type[] { typeof(double), typeof(double), typeof(double), typeof(double) }); + return new InstanceDescriptor(ci, new object[] { keySpline.ControlPoint1.X, keySpline.ControlPoint1.Y, keySpline.ControlPoint2.X, keySpline.ControlPoint2.Y }); } } - // Pass unhandled cases to base class (which will throw exceptions for null value or destinationType.) + // Pass unhandled cases to base class (which will throw exceptions for null value or destinationType) return base.ConvertTo(context, cultureInfo, value, destinationType); } + + /// + /// Converts to its representation using the specified . + /// + /// The to convert to string. + /// Culture to use when formatting doubles and choosing separator. + /// The formatted as using the specified . + private static string ToString(KeySpline keySpline, CultureInfo cultureInfo) + { + string listSeparator = cultureInfo != null ? cultureInfo.TextInfo.ListSeparator : CultureInfo.InvariantCulture.TextInfo.ListSeparator; + + // Initial capacity [64] is an estimate based on a sum of: + // 60 = 4x double (fifteen digits is generous for the range of values) + // 3 = 3x separator characters + // 1 = 1x scratch space for alignment + DefaultInterpolatedStringHandler handler = new(3, 4, cultureInfo, stackalloc char[64]); + handler.AppendFormatted(keySpline.ControlPoint1.X); + handler.AppendLiteral(listSeparator); + + handler.AppendFormatted(keySpline.ControlPoint1.Y); + handler.AppendLiteral(listSeparator); + + handler.AppendFormatted(keySpline.ControlPoint2.X); + handler.AppendLiteral(listSeparator); + + handler.AppendFormatted(keySpline.ControlPoint2.Y); + + return handler.ToStringAndClear(); + } } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/DoubleCollection.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/DoubleCollection.cs index 4190fb47727..01fa0639317 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/DoubleCollection.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/DoubleCollection.cs @@ -713,14 +713,14 @@ public static DoubleCollection Parse(string source) { IFormatProvider formatProvider = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; - TokenizerHelper th = new TokenizerHelper(source, formatProvider); + ValueTokenizerHelper tokenizer = new(source, formatProvider); DoubleCollection resource = new DoubleCollection(); double value; - while (th.NextToken()) + while (tokenizer.NextToken()) { - value = Convert.ToDouble(th.GetCurrentToken(), formatProvider); + value = double.Parse(tokenizer.GetCurrentToken(), formatProvider); resource.Add(value); } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/GradientStopCollection.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/GradientStopCollection.cs index a438fb4514c..5439faf8d2e 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/GradientStopCollection.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/GradientStopCollection.cs @@ -796,16 +796,16 @@ public static GradientStopCollection Parse(string source) { IFormatProvider formatProvider = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; - TokenizerHelper th = new TokenizerHelper(source, formatProvider); + ValueTokenizerHelper tokenizer = new(source, formatProvider); GradientStopCollection resource = new GradientStopCollection(); GradientStop value; - while (th.NextToken()) + while (tokenizer.NextToken()) { value = new GradientStop( - Parsers.ParseColor(th.GetCurrentToken(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider)); + Parsers.ParseColor(tokenizer.GetCurrentToken().ToString(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider)); resource.Add(value); } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/Int32Collection.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/Int32Collection.cs index 6cf347c2c3d..f955c45bdc4 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/Int32Collection.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/Int32Collection.cs @@ -713,14 +713,14 @@ public static Int32Collection Parse(string source) { IFormatProvider formatProvider = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; - TokenizerHelper th = new TokenizerHelper(source, formatProvider); + ValueTokenizerHelper tokenizer = new(source, formatProvider); Int32Collection resource = new Int32Collection(); int value; - while (th.NextToken()) + while (tokenizer.NextToken()) { - value = Convert.ToInt32(th.GetCurrentToken(), formatProvider); + value = Int32.Parse(tokenizer.GetCurrentToken(), formatProvider); resource.Add(value); } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/PointCollection.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/PointCollection.cs index 60659216a64..33a91d28bce 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/PointCollection.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/PointCollection.cs @@ -713,16 +713,16 @@ public static PointCollection Parse(string source) { IFormatProvider formatProvider = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; - TokenizerHelper th = new TokenizerHelper(source, formatProvider); + ValueTokenizerHelper tokenizer = new(source, formatProvider); PointCollection resource = new PointCollection(); Point value; - while (th.NextToken()) + while (tokenizer.NextToken()) { value = new Point( - Convert.ToDouble(th.GetCurrentToken(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider)); + double.Parse(tokenizer.GetCurrentToken(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider)); resource.Add(value); } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/VectorCollection.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/VectorCollection.cs index 4b51cfe5924..07d098f3746 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/VectorCollection.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/VectorCollection.cs @@ -713,16 +713,16 @@ public static VectorCollection Parse(string source) { IFormatProvider formatProvider = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; - TokenizerHelper th = new TokenizerHelper(source, formatProvider); + ValueTokenizerHelper tokenizer = new(source, formatProvider); VectorCollection resource = new VectorCollection(); Vector value; - while (th.NextToken()) + while (tokenizer.NextToken()) { value = new Vector( - Convert.ToDouble(th.GetCurrentToken(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider)); + double.Parse(tokenizer.GetCurrentToken(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider)); resource.Add(value); } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Matrix3D.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Matrix3D.cs index 6b9662b751e..33b8ac9b0bf 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Matrix3D.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Matrix3D.cs @@ -211,41 +211,41 @@ public static Matrix3D Parse(string source) { IFormatProvider formatProvider = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; - TokenizerHelper th = new TokenizerHelper(source, formatProvider); + ValueTokenizerHelper tokenizer = new(source, formatProvider); Matrix3D value; - String firstToken = th.NextTokenRequired(); + ReadOnlySpan firstToken = tokenizer.NextTokenRequired(); // The token will already have had whitespace trimmed so we can do a // simple string compare. - if (firstToken == "Identity") + if (firstToken.Equals("Identity", StringComparison.Ordinal)) { value = Identity; } else { value = new Matrix3D( - Convert.ToDouble(firstToken, formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider)); + double.Parse(firstToken, formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider)); } // There should be no more tokens in this string. - th.LastTokenRequired(); + tokenizer.LastTokenRequired(); return value; } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Point3D.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Point3D.cs index 84b1d3950a1..ff293a54fd6 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Point3D.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Point3D.cs @@ -151,19 +151,19 @@ public static Point3D Parse(string source) { IFormatProvider formatProvider = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; - TokenizerHelper th = new TokenizerHelper(source, formatProvider); + ValueTokenizerHelper tokenizer = new(source, formatProvider); Point3D value; - String firstToken = th.NextTokenRequired(); + ReadOnlySpan firstToken = tokenizer.NextTokenRequired(); value = new Point3D( - Convert.ToDouble(firstToken, formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider)); + double.Parse(firstToken, formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider)); // There should be no more tokens in this string. - th.LastTokenRequired(); + tokenizer.LastTokenRequired(); return value; } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Point3DCollection.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Point3DCollection.cs index 5439f64bde9..3f0890efe8d 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Point3DCollection.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Point3DCollection.cs @@ -711,17 +711,17 @@ public static Point3DCollection Parse(string source) { IFormatProvider formatProvider = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; - TokenizerHelper th = new TokenizerHelper(source, formatProvider); + ValueTokenizerHelper tokenizer = new(source, formatProvider); Point3DCollection resource = new Point3DCollection(); Point3D value; - while (th.NextToken()) + while (tokenizer.NextToken()) { value = new Point3D( - Convert.ToDouble(th.GetCurrentToken(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider)); + double.Parse(tokenizer.GetCurrentToken(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider)); resource.Add(value); } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Point4D.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Point4D.cs index f5cdf6e27ed..e70f2bbc21b 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Point4D.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Point4D.cs @@ -154,20 +154,20 @@ public static Point4D Parse(string source) { IFormatProvider formatProvider = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; - TokenizerHelper th = new TokenizerHelper(source, formatProvider); + ValueTokenizerHelper tokenizer = new(source, formatProvider); Point4D value; - String firstToken = th.NextTokenRequired(); + ReadOnlySpan firstToken = tokenizer.NextTokenRequired(); value = new Point4D( - Convert.ToDouble(firstToken, formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider)); + double.Parse(firstToken, formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider)); // There should be no more tokens in this string. - th.LastTokenRequired(); + tokenizer.LastTokenRequired(); return value; } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Quaternion.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Quaternion.cs index df034c6c5f5..9dcf6a45a1a 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Quaternion.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Quaternion.cs @@ -175,29 +175,29 @@ public static Quaternion Parse(string source) { IFormatProvider formatProvider = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; - TokenizerHelper th = new TokenizerHelper(source, formatProvider); + ValueTokenizerHelper tokenizer = new(source, formatProvider); Quaternion value; - String firstToken = th.NextTokenRequired(); + ReadOnlySpan firstToken = tokenizer.NextTokenRequired(); // The token will already have had whitespace trimmed so we can do a // simple string compare. - if (firstToken == "Identity") + if (firstToken.Equals("Identity", StringComparison.Ordinal)) { value = Identity; } else { value = new Quaternion( - Convert.ToDouble(firstToken, formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider)); + double.Parse(firstToken, formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider)); } // There should be no more tokens in this string. - th.LastTokenRequired(); + tokenizer.LastTokenRequired(); return value; } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Rect3D.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Rect3D.cs index d7089f8f815..97845f15650 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Rect3D.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Rect3D.cs @@ -174,31 +174,31 @@ public static Rect3D Parse(string source) { IFormatProvider formatProvider = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; - TokenizerHelper th = new TokenizerHelper(source, formatProvider); + ValueTokenizerHelper tokenizer = new(source, formatProvider); Rect3D value; - String firstToken = th.NextTokenRequired(); + ReadOnlySpan firstToken = tokenizer.NextTokenRequired(); // The token will already have had whitespace trimmed so we can do a // simple string compare. - if (firstToken == "Empty") + if (firstToken.Equals("Empty", StringComparison.Ordinal)) { value = Empty; } else { value = new Rect3D( - Convert.ToDouble(firstToken, formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider)); + double.Parse(firstToken, formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider)); } // There should be no more tokens in this string. - th.LastTokenRequired(); + tokenizer.LastTokenRequired(); return value; } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Size3D.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Size3D.cs index 8be93cda490..fd0f19fc1e3 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Size3D.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Size3D.cs @@ -165,28 +165,28 @@ public static Size3D Parse(string source) { IFormatProvider formatProvider = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; - TokenizerHelper th = new TokenizerHelper(source, formatProvider); + ValueTokenizerHelper tokenizer = new(source, formatProvider); Size3D value; - String firstToken = th.NextTokenRequired(); + ReadOnlySpan firstToken = tokenizer.NextTokenRequired(); // The token will already have had whitespace trimmed so we can do a // simple string compare. - if (firstToken == "Empty") + if (firstToken.Equals("Empty", StringComparison.Ordinal)) { value = Empty; } else { value = new Size3D( - Convert.ToDouble(firstToken, formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider)); + double.Parse(firstToken, formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider)); } // There should be no more tokens in this string. - th.LastTokenRequired(); + tokenizer.LastTokenRequired(); return value; } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Vector3D.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Vector3D.cs index 31e735152cc..dd27124631f 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Vector3D.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Vector3D.cs @@ -151,19 +151,19 @@ public static Vector3D Parse(string source) { IFormatProvider formatProvider = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; - TokenizerHelper th = new TokenizerHelper(source, formatProvider); + ValueTokenizerHelper tokenizer = new(source, formatProvider); Vector3D value; - String firstToken = th.NextTokenRequired(); + ReadOnlySpan firstToken = tokenizer.NextTokenRequired(); value = new Vector3D( - Convert.ToDouble(firstToken, formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider)); + double.Parse(firstToken, formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider)); // There should be no more tokens in this string. - th.LastTokenRequired(); + tokenizer.LastTokenRequired(); return value; } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Vector3DCollection.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Vector3DCollection.cs index 32cd5910d9c..9fc556342de 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Vector3DCollection.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Vector3DCollection.cs @@ -711,17 +711,17 @@ public static Vector3DCollection Parse(string source) { IFormatProvider formatProvider = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; - TokenizerHelper th = new TokenizerHelper(source, formatProvider); + ValueTokenizerHelper tokenizer = new(source, formatProvider); Vector3DCollection resource = new Vector3DCollection(); Vector3D value; - while (th.NextToken()) + while (tokenizer.NextToken()) { value = new Vector3D( - Convert.ToDouble(th.GetCurrentToken(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider)); + double.Parse(tokenizer.GetCurrentToken(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider)); resource.Add(value); } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/VirtualizationCacheLengthConverter.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/VirtualizationCacheLengthConverter.cs index fc78d576106..57bcc7b4328 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/VirtualizationCacheLengthConverter.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/VirtualizationCacheLengthConverter.cs @@ -1,22 +1,17 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// -// Description: Virtualization cache length converter implementation -// - -using MS.Internal; -using System.ComponentModel; using System.ComponentModel.Design.Serialization; +using System.ComponentModel; using System.Globalization; using System.Reflection; +using MS.Internal; namespace System.Windows.Controls { /// - /// VirtualizationCacheLengthConverter - Converter class for converting - /// instances of other types to and from VirtualizationCacheLength instances. - /// + /// Converter class for converting instances of other types to and from instances. + /// public class VirtualizationCacheLengthConverter : TypeConverter { #region Public Methods @@ -25,10 +20,10 @@ public class VirtualizationCacheLengthConverter : TypeConverter /// CanConvertFrom - Returns whether or not this class can convert from a given type. /// /// - /// bool - True if thie converter can convert from the provided type, false if not. + /// if the given can be converted from, otherwise. /// - /// The ITypeDescriptorContext for this call. - /// The Type being queried for support. + /// The for this call. + /// The being queried for support. public override bool CanConvertFrom(ITypeDescriptorContext typeDescriptorContext, Type sourceType) { // We can only handle strings, integral and floating types @@ -63,15 +58,7 @@ public override bool CanConvertFrom(ITypeDescriptorContext typeDescriptorContext public override bool CanConvertTo(ITypeDescriptorContext typeDescriptorContext, Type destinationType) { // We can convert to an InstanceDescriptor or to a string. - if ( destinationType == typeof(InstanceDescriptor) - || destinationType == typeof(string)) - { - return true; - } - else - { - return false; - } + return destinationType == typeof(InstanceDescriptor) || destinationType == typeof(string); } /// @@ -92,20 +79,14 @@ public override bool CanConvertTo(ITypeDescriptorContext typeDescriptorContext, /// The object to convert to a VirtualizationCacheLength. public override object ConvertFrom(ITypeDescriptorContext typeDescriptorContext, CultureInfo cultureInfo, object source) { - if (source != null) - { - if (source is string) - { - return (FromString((string)source, cultureInfo)); - } - else - { - // conversion from numeric type - double value = Convert.ToDouble(source, cultureInfo); - return new VirtualizationCacheLength(value); - } - } - throw GetConvertFromException(source); + if (source is null) + throw GetConvertFromException(source); + + if (source is string stringValue) + return FromString(stringValue, cultureInfo); + + // Conversion from a numeric type + return new VirtualizationCacheLength(Convert.ToDouble(source, cultureInfo)); } /// @@ -129,23 +110,20 @@ public override object ConvertTo(ITypeDescriptorContext typeDescriptorContext, C { ArgumentNullException.ThrowIfNull(destinationType); - if (value != null - && value is VirtualizationCacheLength) + if (value is not VirtualizationCacheLength cacheLength) + throw GetConvertToException(value, destinationType); + + if (destinationType == typeof(string)) + return ToString(cacheLength, cultureInfo); + + if (destinationType == typeof(InstanceDescriptor)) { - VirtualizationCacheLength gl = (VirtualizationCacheLength)value; - - if (destinationType == typeof(string)) - { - return (ToString(gl, cultureInfo)); - } - - if (destinationType == typeof(InstanceDescriptor)) - { - ConstructorInfo ci = typeof(VirtualizationCacheLength).GetConstructor(new Type[] { typeof(double), typeof(VirtualizationCacheLengthUnit) }); - return (new InstanceDescriptor(ci, new object[] { gl.CacheBeforeViewport, gl.CacheAfterViewport })); - } + ConstructorInfo ci = typeof(VirtualizationCacheLength).GetConstructor(new Type[] { typeof(double), typeof(VirtualizationCacheLengthUnit) }); + return new InstanceDescriptor(ci, new object[] { cacheLength.CacheBeforeViewport, cacheLength.CacheAfterViewport }); } - throw GetConvertToException(value, destinationType); + + // This will just throw an exception but it is a pattern + return base.ConvertTo(typeDescriptorContext, cultureInfo, value, destinationType); } @@ -169,50 +147,40 @@ internal static string ToString(VirtualizationCacheLength cacheLength, CultureIn { char listSeparator = TokenizerHelper.GetNumericListSeparator(cultureInfo); - return string.Create(cultureInfo, stackalloc char[128], - $"{cacheLength.CacheBeforeViewport}{listSeparator}{cacheLength.CacheAfterViewport}"); + return string.Create(cultureInfo, stackalloc char[128], $"{cacheLength.CacheBeforeViewport}{listSeparator}{cacheLength.CacheAfterViewport}"); } + /// - /// Parses a VirtualizationCacheLength from a string given the CultureInfo. + /// Parses a from a given the . /// - /// String to parse from. - /// Culture Info. - /// Newly created VirtualizationCacheLength instance. - internal static VirtualizationCacheLength FromString(string s, CultureInfo cultureInfo) + /// to parse from. + /// The that is respected during parsing. + /// A new instance of . + internal static VirtualizationCacheLength FromString(string input, CultureInfo cultureInfo) { - TokenizerHelper th = new TokenizerHelper(s, cultureInfo); - double[] lengths = new double[2]; + ValueTokenizerHelper tokenizer = new(input, cultureInfo); + Span lengths = stackalloc double[2]; int i = 0; // Peel off each double in the delimited list. - while (th.NextToken()) + while (tokenizer.NextToken()) { if (i >= 2) - { - i = 3; // Set i to a bad value. - break; - } + throw new FormatException(SR.Format(SR.InvalidStringVirtualizationCacheLength, input)); - lengths[i] = Double.Parse(th.GetCurrentToken(), cultureInfo); + lengths[i] = double.Parse(tokenizer.GetCurrentToken(), cultureInfo); i++; } - // We have a reasonable interpreation for one value (all four edges), two values (horizontal, vertical), - // and four values (left, top, right, bottom). - switch (i) + return i switch { - case 1: - return new VirtualizationCacheLength(lengths[0]); - - case 2: - // Should allowInfinity be false ??? (Rob) - return new VirtualizationCacheLength(lengths[0], lengths[1]); - } - - throw new FormatException(SR.Format(SR.InvalidStringVirtualizationCacheLength, s)); + 1 => new VirtualizationCacheLength(lengths[0]), + 2 => new VirtualizationCacheLength(lengths[0], lengths[1]), + _ => throw new FormatException(SR.Format(SR.InvalidStringVirtualizationCacheLength, input)), + }; } - #endregion + #endregion } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/CornerRadiusConverter.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/CornerRadiusConverter.cs index 24f7d3401ff..a4ef35ce582 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/CornerRadiusConverter.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/CornerRadiusConverter.cs @@ -1,8 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.ComponentModel; using System.ComponentModel.Design.Serialization; +using System.ComponentModel; using System.Globalization; using System.Reflection; using MS.Internal; @@ -10,7 +10,7 @@ namespace System.Windows { /// - /// CornerRadiusConverter - Converter class for converting instances of other types to and from CornerRadius instances. + /// Converter class for converting instances of other types to and from instances. /// public class CornerRadiusConverter : TypeConverter { @@ -20,10 +20,10 @@ public class CornerRadiusConverter : TypeConverter /// CanConvertFrom - Returns whether or not this class can convert from a given type. /// /// - /// bool - True if thie converter can convert from the provided type, false if not. + /// if the given can be converted from, otherwise. /// - /// The ITypeDescriptorContext for this call. - /// The Type being queried for support. + /// The for this call. + /// The being queried for support. public override bool CanConvertFrom(ITypeDescriptorContext typeDescriptorContext, Type sourceType) { // We can only handle strings, integral and floating types @@ -58,15 +58,7 @@ public override bool CanConvertFrom(ITypeDescriptorContext typeDescriptorContext public override bool CanConvertTo(ITypeDescriptorContext typeDescriptorContext, Type destinationType) { // We can convert to an InstanceDescriptor or to a string. - if ( destinationType == typeof(InstanceDescriptor) - || destinationType == typeof(string)) - { - return true; - } - else - { - return false; - } + return destinationType == typeof(InstanceDescriptor) || destinationType == typeof(string); } /// @@ -87,12 +79,14 @@ public override bool CanConvertTo(ITypeDescriptorContext typeDescriptorContext, /// The object to convert to a CornerRadius. public override object ConvertFrom(ITypeDescriptorContext typeDescriptorContext, CultureInfo cultureInfo, object source) { - if (source != null) - { - if (source is string) { return FromString((string)source, cultureInfo); } - else { return new CornerRadius(Convert.ToDouble(source, cultureInfo)); } - } - throw GetConvertFromException(source); + if (source is null) + throw GetConvertFromException(source); + + if (source is string stringValue) + return FromString(stringValue, cultureInfo); + + // Conversion from a numeric type + return new CornerRadius(Convert.ToDouble(source, cultureInfo)); } /// @@ -115,20 +109,18 @@ public override object ConvertFrom(ITypeDescriptorContext typeDescriptorContext, public override object ConvertTo(ITypeDescriptorContext typeDescriptorContext, CultureInfo cultureInfo, object value, Type destinationType) { ArgumentNullException.ThrowIfNull(value); - ArgumentNullException.ThrowIfNull(destinationType); - if (!(value is CornerRadius)) - { + if (value is not CornerRadius cornerRadius) throw new ArgumentException(SR.Format(SR.UnexpectedParameterType, value.GetType(), typeof(CornerRadius)), nameof(value)); - } - CornerRadius cr = (CornerRadius)value; - if (destinationType == typeof(string)) { return ToString(cr, cultureInfo); } + if (destinationType == typeof(string)) + return ToString(cornerRadius, cultureInfo); + if (destinationType == typeof(InstanceDescriptor)) { ConstructorInfo ci = typeof(CornerRadius).GetConstructor(new Type[] { typeof(double), typeof(double), typeof(double), typeof(double) }); - return new InstanceDescriptor(ci, new object[] { cr.TopLeft, cr.TopRight, cr.BottomRight, cr.BottomLeft }); + return new InstanceDescriptor(ci, new object[] { cornerRadius.TopLeft, cornerRadius.TopRight, cornerRadius.BottomRight, cornerRadius.BottomLeft }); } throw new ArgumentException(SR.Format(SR.CannotConvertType, typeof(CornerRadius), destinationType.FullName)); @@ -151,37 +143,36 @@ internal static string ToString(CornerRadius cr, CultureInfo cultureInfo) return string.Create(cultureInfo, stackalloc char[64], $"{cr.TopLeft}{listSeparator}{cr.TopRight}{listSeparator}{cr.BottomRight}{listSeparator}{cr.BottomLeft}"); } - internal static CornerRadius FromString(string s, CultureInfo cultureInfo) + /// + /// Parses a from a given the . + /// + /// to parse from. + /// The that is respected during parsing. + /// A new instance of . + internal static CornerRadius FromString(string input, CultureInfo cultureInfo) { - TokenizerHelper th = new TokenizerHelper(s, cultureInfo); - double[] radii = new double[4]; + ValueTokenizerHelper tokenizer = new(input, cultureInfo); + Span radii = stackalloc double[4]; int i = 0; // Peel off each Length in the delimited list. - while (th.NextToken()) + while (tokenizer.NextToken()) { if (i >= 4) - { - i = 5; // Set i to a bad value. - break; - } + throw new FormatException(SR.Format(SR.InvalidStringCornerRadius, input)); - radii[i] = double.Parse(th.GetCurrentToken(), cultureInfo); + radii[i] = double.Parse(tokenizer.GetCurrentToken(), cultureInfo); i++; } // We have a reasonable interpreation for one value (all four edges) // and four values (left, top, right, bottom). - switch (i) + return i switch { - case 1: - return (new CornerRadius(radii[0])); - - case 4: - return (new CornerRadius(radii[0], radii[1], radii[2], radii[3])); - } - - throw new FormatException(SR.Format(SR.InvalidStringCornerRadius, s)); + 1 => new CornerRadius(radii[0]), + 4 => new CornerRadius(radii[0], radii[1], radii[2], radii[3]), + _ => throw new FormatException(SR.Format(SR.InvalidStringCornerRadius, input)), + }; } #endregion } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/LengthConverter.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/LengthConverter.cs index da2652e9062..a70a2c3aac6 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/LengthConverter.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/LengthConverter.cs @@ -1,27 +1,19 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// -// -// -// Description: Contains the LengthConverter: TypeConverter for the Length class. -// -// - -using System.ComponentModel; using System.ComponentModel.Design.Serialization; using System.Runtime.CompilerServices; +using System.ComponentModel; using System.Globalization; using System.Reflection; using MS.Internal; namespace System.Windows { - /// /// LengthConverter - Converter class for converting instances of other types to and from double representing length. /// - public class LengthConverter: TypeConverter + public class LengthConverter : TypeConverter { //------------------------------------------------------------------- // @@ -56,7 +48,7 @@ public override bool CanConvertFrom(ITypeDescriptorContext typeDescriptorContext case TypeCode.UInt32: case TypeCode.UInt64: return true; - default: + default: return false; } } @@ -69,18 +61,10 @@ public override bool CanConvertFrom(ITypeDescriptorContext typeDescriptorContext /// /// The ITypeDescriptorContext for this call. /// The Type being queried for support. - public override bool CanConvertTo(ITypeDescriptorContext typeDescriptorContext, Type destinationType) + public override bool CanConvertTo(ITypeDescriptorContext typeDescriptorContext, Type destinationType) { // We can convert to an InstanceDescriptor or to a string. - if (destinationType == typeof(InstanceDescriptor) || - destinationType == typeof(string)) - { - return true; - } - else - { - return false; - } + return destinationType == typeof(InstanceDescriptor) || destinationType == typeof(string); } /// @@ -99,17 +83,16 @@ public override bool CanConvertTo(ITypeDescriptorContext typeDescriptorContext, /// The ITypeDescriptorContext for this call. /// The CultureInfo which is respected when converting. /// The object to convert to a double. - public override object ConvertFrom(ITypeDescriptorContext typeDescriptorContext, - CultureInfo cultureInfo, - object source) + public override object ConvertFrom(ITypeDescriptorContext typeDescriptorContext, CultureInfo cultureInfo, object source) { - if (source != null) - { - if (source is string) { return FromString((string)source, cultureInfo); } - else { return (double)(Convert.ToDouble(source, cultureInfo)); } - } + if (source is null) + throw GetConvertFromException(source); + + if (source is string sourceString) + return FromString(sourceString, cultureInfo); - throw GetConvertFromException(source); + // Conversion from a numeric type + return Convert.ToDouble(source, cultureInfo); } /// @@ -129,31 +112,24 @@ public override object ConvertFrom(ITypeDescriptorContext typeDescriptorContext, /// The CultureInfo which is respected when converting. /// The double to convert. /// The type to which to convert the double. - public override object ConvertTo(ITypeDescriptorContext typeDescriptorContext, - CultureInfo cultureInfo, - object value, - Type destinationType) + public override object ConvertTo(ITypeDescriptorContext typeDescriptorContext, CultureInfo cultureInfo, object value, Type destinationType) { ArgumentNullException.ThrowIfNull(destinationType); - if ( value != null - && value is double ) + if (value is not double doubleValue) + throw GetConvertToException(value, destinationType); + + if (destinationType == typeof(string)) + return ToString(doubleValue, cultureInfo); + + if (destinationType == typeof(InstanceDescriptor)) { - double l = (double)value; - if (destinationType == typeof(string)) - { - if(double.IsNaN(l)) - return "Auto"; - else - return Convert.ToString(l, cultureInfo); - } - else if (destinationType == typeof(InstanceDescriptor)) - { - ConstructorInfo ci = typeof(double).GetConstructor(new Type[] { typeof(double) }); - return new InstanceDescriptor(ci, new object[] { l }); - } + ConstructorInfo ci = typeof(double).GetConstructor(new Type[] { typeof(double) }); + return new InstanceDescriptor(ci, new object[] { doubleValue }); } - throw GetConvertToException(value, destinationType); + + // This will just throw an exception but it is a pattern + return base.ConvertTo(typeDescriptorContext, cultureInfo, value, destinationType); } #endregion @@ -165,6 +141,21 @@ public override object ConvertTo(ITypeDescriptorContext typeDescriptorContext, #region Internal Methods + /// + /// Formats a single to length representation. + /// For values, "Auto" is returned instead. + /// + /// The value to format as string. + /// The handler specifying culture used for conversion. + /// Formatted length representation of the . + internal static string ToString(double value, CultureInfo cultureInfo) + { + if (double.IsNaN(value)) + return "Auto"; + + return Convert.ToString(value, cultureInfo); + } + /// Format into using specified /// in .

/// Special representation applies for values, emitted as "Auto" string instead.
@@ -184,22 +175,21 @@ internal static void FormatLengthAsString(double value, ref DefaultInterpolatedS // [value] is a double // [unit] is a string specifying the unit, like 'in' or 'px', or nothing (means pixels) // NOTE - This code is called from FontSizeConverter, so changes will affect both. - internal static double FromString(string s, CultureInfo cultureInfo) + internal static double FromString(ReadOnlySpan value, CultureInfo cultureInfo) { - ReadOnlySpan valueSpan = s.AsSpan().Trim(); + ReadOnlySpan valueSpan = value.Trim(); double unitFactor = 1.0; - //Auto is represented and Double.NaN - //properties that do not want Auto and NaN to be in their ligit values, - //should disallow NaN in validation callbacks (same goes for negative values) - if (valueSpan.Equals("auto", StringComparison.OrdinalIgnoreCase)) - return Double.NaN; - - PixelUnit pixelUnit; - if (PixelUnit.TryParsePixel(valueSpan, out pixelUnit) - || PixelUnit.TryParsePixelPerInch(valueSpan, out pixelUnit) - || PixelUnit.TryParsePixelPerCentimeter(valueSpan, out pixelUnit) - || PixelUnit.TryParsePixelPerPoint(valueSpan, out pixelUnit)) + // Auto is represented as Double.NaN + // Properties that do not want Auto and NaN to be in their ligit values, + // should disallow NaN in validation callbacks (same goes for negative values) + if (valueSpan.Equals("Auto", StringComparison.OrdinalIgnoreCase)) + return double.NaN; + + if (PixelUnit.TryParsePixel(valueSpan, out PixelUnit pixelUnit) || + PixelUnit.TryParsePixelPerInch(valueSpan, out pixelUnit) || + PixelUnit.TryParsePixelPerCentimeter(valueSpan, out pixelUnit) || + PixelUnit.TryParsePixelPerPoint(valueSpan, out pixelUnit)) { valueSpan = valueSpan.Slice(0, valueSpan.Length - pixelUnit.Name.Length); unitFactor = pixelUnit.Factor; @@ -215,7 +205,7 @@ private static double ParseDouble(ReadOnlySpan span, CultureInfo cultureIn { // FormatException errors thrown by double.Parse are pretty uninformative. // Throw a more meaningful error in this case that tells that we were attempting - // to create a Length instance from a string. This addresses windows bug 968884 + // to create a Length instance from a string. This addresses windows bug 968884 try { return double.Parse(span, cultureInfo); @@ -226,7 +216,6 @@ private static double ParseDouble(ReadOnlySpan span, CultureInfo cultureIn } } - #endregion } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/ThicknessConverter.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/ThicknessConverter.cs index 8acc47e454a..afb84a5ed2b 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/ThicknessConverter.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/ThicknessConverter.cs @@ -1,16 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// -// -// -// Description: Contains the ThicknessConverter: TypeConverter for the Thickness struct. -// -// - -using System.ComponentModel; using System.ComponentModel.Design.Serialization; using System.Runtime.CompilerServices; +using System.ComponentModel; using System.Globalization; using System.Reflection; using MS.Internal; @@ -18,20 +11,20 @@ namespace System.Windows { /// - /// ThicknessConverter - Converter class for converting instances of other types to and from Thickness instances. + /// Converter class for converting instances of other types to and from instances. /// public class ThicknessConverter : TypeConverter { #region Public Methods /// - /// CanConvertFrom - Returns whether or not this class can convert from a given type. + /// Returns whether this class can convert specific into . /// /// - /// bool - True if thie converter can convert from the provided type, false if not. + /// if the given can be converted from, otherwise. /// - /// The ITypeDescriptorContext for this call. - /// The Type being queried for support. + /// The for this call. + /// The being queried for support. public override bool CanConvertFrom(ITypeDescriptorContext typeDescriptorContext, Type sourceType) { // We can only handle strings, integral and floating types @@ -92,18 +85,24 @@ public override object ConvertFrom(ITypeDescriptorContext typeDescriptorContext, if (source is string sourceString) return FromString(sourceString, cultureInfo); - else if (source is double sourceValue) + + if (source is double sourceValue) return new Thickness(sourceValue); - else - return new Thickness(Convert.ToDouble(source, cultureInfo)); + + // Conversion from a numeric type + return new Thickness(Convert.ToDouble(source, cultureInfo)); } /// - /// ConvertTo - Attempt to convert a Thickness to the given type + /// Attempt to convert a struct to the . /// /// - /// The object which was constructed. + /// The formatted as using the specified or an . /// + /// The ITypeDescriptorContext for this call. + /// The CultureInfo which is respected when converting. + /// The Thickness to convert. + /// The type to which to convert the Thickness instance. /// /// An ArgumentNullException is thrown if the example object is null. /// @@ -111,10 +110,6 @@ public override object ConvertFrom(ITypeDescriptorContext typeDescriptorContext, /// An ArgumentException is thrown if the object is not null and is not a Thickness, /// or if the destinationType isn't one of the valid destination types. /// - /// The ITypeDescriptorContext for this call. - /// The CultureInfo which is respected when converting. - /// The Thickness to convert. - /// The type to which to convert the Thickness instance. public override object ConvertTo(ITypeDescriptorContext typeDescriptorContext, CultureInfo cultureInfo, object value, Type destinationType) { ArgumentNullException.ThrowIfNull(value); @@ -125,7 +120,8 @@ public override object ConvertTo(ITypeDescriptorContext typeDescriptorContext, C if (destinationType == typeof(string)) return ToString(thickness, cultureInfo); - else if (destinationType == typeof(InstanceDescriptor)) + + if (destinationType == typeof(InstanceDescriptor)) { ConstructorInfo ci = typeof(Thickness).GetConstructor(new Type[] { typeof(double), typeof(double), typeof(double), typeof(double) }); return new InstanceDescriptor(ci, new object[] { thickness.Left, thickness.Top, thickness.Right, thickness.Bottom }); @@ -134,7 +130,6 @@ public override object ConvertTo(ITypeDescriptorContext typeDescriptorContext, C throw new ArgumentException(SR.Format(SR.CannotConvertType, typeof(Thickness), destinationType.FullName)); } - #endregion Public Methods //------------------------------------------------------------------- @@ -146,12 +141,12 @@ public override object ConvertTo(ITypeDescriptorContext typeDescriptorContext, C #region Internal Methods /// - /// Converts to its string representation using the specified . + /// Converts to its string representation using the specified . /// - /// The to convert to string. + /// The to convert to . /// Culture to use when formatting doubles and choosing separator. - /// The formatted as string using the specified . - internal static string ToString(Thickness th, CultureInfo cultureInfo) + /// The formatted as using the specified . + internal static string ToString(Thickness thickness, CultureInfo cultureInfo) { char listSeparator = TokenizerHelper.GetNumericListSeparator(cultureInfo); @@ -162,40 +157,40 @@ internal static string ToString(Thickness th, CultureInfo cultureInfo) // 1 = 1x scratch space for alignment DefaultInterpolatedStringHandler handler = new(0, 7, cultureInfo, stackalloc char[64]); - LengthConverter.FormatLengthAsString(th.Left, ref handler); + LengthConverter.FormatLengthAsString(thickness.Left, ref handler); handler.AppendFormatted(listSeparator); - LengthConverter.FormatLengthAsString(th.Top, ref handler); + LengthConverter.FormatLengthAsString(thickness.Top, ref handler); handler.AppendFormatted(listSeparator); - LengthConverter.FormatLengthAsString(th.Right, ref handler); + LengthConverter.FormatLengthAsString(thickness.Right, ref handler); handler.AppendFormatted(listSeparator); - LengthConverter.FormatLengthAsString(th.Bottom, ref handler); + LengthConverter.FormatLengthAsString(thickness.Bottom, ref handler); return handler.ToStringAndClear(); } /// - /// Constructs a struct out of string representation supplied by and the specified . + /// Constructs a struct out of string representation supplied by and the specified . /// - /// The string representation of a struct. + /// The string representation of a struct. /// The which was used to format this string. - /// A new instance of struct representing the data contained in . - /// Thrown when contains invalid string representation. - internal static Thickness FromString(string s, CultureInfo cultureInfo) + /// A new instance of struct representing the data contained in . + /// Thrown when contains invalid string representation. + internal static Thickness FromString(string input, CultureInfo cultureInfo) { - TokenizerHelper th = new(s, cultureInfo); + ValueTokenizerHelper tokenizer = new(input, cultureInfo); Span lengths = stackalloc double[4]; int i = 0; // Peel off each double in the delimited list. - while (th.NextToken()) + while (tokenizer.NextToken()) { if (i >= 4) // In case we've got more than 4 doubles, we throw - throw new FormatException(SR.Format(SR.InvalidStringThickness, s)); + throw new FormatException(SR.Format(SR.InvalidStringThickness, input)); - lengths[i] = LengthConverter.FromString(th.GetCurrentToken(), cultureInfo); + lengths[i] = LengthConverter.FromString(tokenizer.GetCurrentToken(), cultureInfo); i++; } @@ -207,11 +202,10 @@ internal static Thickness FromString(string s, CultureInfo cultureInfo) 1 => new Thickness(lengths[0]), 2 => new Thickness(lengths[0], lengths[1], lengths[0], lengths[1]), 4 => new Thickness(lengths[0], lengths[1], lengths[2], lengths[3]), - _ => throw new FormatException(SR.Format(SR.InvalidStringThickness, s)), + _ => throw new FormatException(SR.Format(SR.InvalidStringThickness, input)), }; } - #endregion - + #endregion } } diff --git a/src/Microsoft.DotNet.Wpf/src/Shared/MS/Internal/TokenizerHelper.cs b/src/Microsoft.DotNet.Wpf/src/Shared/MS/Internal/TokenizerHelper.cs index c402f8ba7ce..478067cf776 100644 --- a/src/Microsoft.DotNet.Wpf/src/Shared/MS/Internal/TokenizerHelper.cs +++ b/src/Microsoft.DotNet.Wpf/src/Shared/MS/Internal/TokenizerHelper.cs @@ -18,48 +18,26 @@ namespace MS.Internal.Markup namespace MS.Internal #endif { - internal class TokenizerHelper + internal sealed class TokenizerHelper { /// - /// Constructor for TokenizerHelper which accepts an IFormatProvider. - /// If the IFormatProvider is null, we use the thread's IFormatProvider info. - /// We will use ',' as the list separator, unless it's the same as the - /// decimal separator. If it *is*, then we can't determine if, say, "23,5" is one - /// number or two. In this case, we will use ";" as the separator. + /// Constructor for which accepts an . + /// If the is , we use the thread's info. + /// We will use ',' as the list separator, unless it's the same as the decimal separator. + /// If it *is*, then we can't determine if, say, "23,5" is one number or two. In this case, we will use ";" as the separator. /// /// The string which will be tokenized. - /// The IFormatProvider which controls this tokenization. - internal TokenizerHelper(string str, IFormatProvider formatProvider) - { - char numberSeparator = GetNumericListSeparator(formatProvider); - - Initialize(str, '\'', numberSeparator); - } + /// The which controls this tokenization. + internal TokenizerHelper(string str, IFormatProvider formatProvider) : this(str, '\'', GetNumericListSeparator(formatProvider)) { } /// - /// Initialize the TokenizerHelper with the string to tokenize, + /// Initialize the with the string to tokenize, /// the char which represents quotes and the list separator. /// /// The string to tokenize. /// The quote char. /// The list separator. - internal TokenizerHelper(string str, - char quoteChar, - char separator) - { - Initialize(str, quoteChar, separator); - } - - /// - /// Initialize the TokenizerHelper with the string to tokenize, - /// the char which represents quotes and the list separator. - /// - /// The string to tokenize. - /// The quote char. - /// The list separator. - private void Initialize(string str, - char quoteChar, - char separator) + internal TokenizerHelper(string str, char quoteChar, char separator) { _str = str; _strLen = str == null ? 0 : str.Length; @@ -72,10 +50,8 @@ private void Initialize(string str, // character of the next token. while (_charIndex < _strLen) { - if (!Char.IsWhiteSpace(_str, _charIndex)) - { + if (!char.IsWhiteSpace(_str[_charIndex])) break; - } ++_charIndex; } @@ -91,7 +67,7 @@ internal string GetCurrentToken() return _str.Substring(_currentTokenIndex,_currentTokenLength); } - + /// /// Throws an exception if there is any non-whitespace left un-parsed. /// @@ -99,7 +75,7 @@ internal void LastTokenRequired() { if (_charIndex != _strLen) { - throw new System.InvalidOperationException(SR.Format(SR.TokenizerHelperExtraDataEncountered, _charIndex, _str)); + throw new InvalidOperationException(SR.Format(SR.TokenizerHelperExtraDataEncountered, _charIndex, _str)); } } @@ -120,7 +96,7 @@ internal string NextTokenRequired() { if (!NextToken(false)) { - throw new System.InvalidOperationException(SR.Format(SR.TokenizerHelperPrematureStringTermination, _str)); + throw new InvalidOperationException(SR.Format(SR.TokenizerHelperPrematureStringTermination, _str)); } return GetCurrentToken(); @@ -134,7 +110,7 @@ internal string NextTokenRequired(bool allowQuotedToken) { if (!NextToken(allowQuotedToken)) { - throw new System.InvalidOperationException(SR.Format(SR.TokenizerHelperPrematureStringTermination, _str)); + throw new InvalidOperationException(SR.Format(SR.TokenizerHelperPrematureStringTermination, _str)); } return GetCurrentToken(); @@ -168,15 +144,14 @@ internal bool NextToken(bool allowQuotedToken, char separator) char currentChar = _str[_charIndex]; - Debug.Assert(!Char.IsWhiteSpace(currentChar),"Token started on Whitespace"); + Debug.Assert(!char.IsWhiteSpace(currentChar), "Token started on Whitespace"); // setup the quoteCount int quoteCount = 0; // If we are allowing a quoted token and this token begins with a quote, // set up the quote count and skip the initial quote - if (allowQuotedToken && - currentChar == _quoteChar) + if (allowQuotedToken && _quoteChar == currentChar) { quoteCount++; // increment quote count ++_charIndex; // move to next character @@ -202,14 +177,14 @@ internal bool NextToken(bool allowQuotedToken, char separator) // if at zero which it always should for now // break out of the loop - if (0 == quoteCount) + if (quoteCount == 0) { ++_charIndex; // move past the quote break; } } } - else if ((Char.IsWhiteSpace(currentChar)) || (currentChar == separator)) + else if (char.IsWhiteSpace(currentChar) || (currentChar == separator)) { if (currentChar == separator) { @@ -226,7 +201,7 @@ internal bool NextToken(bool allowQuotedToken, char separator) // before the ending quote if (quoteCount > 0) { - throw new System.InvalidOperationException(SR.Format(SR.TokenizerHelperMissingEndQuote, _str)); + throw new InvalidOperationException(SR.Format(SR.TokenizerHelperMissingEndQuote, _str)); } ScanToNextToken(separator); // move so at the start of the nextToken for next call @@ -237,13 +212,17 @@ internal bool NextToken(bool allowQuotedToken, char separator) if (_currentTokenLength < 1) { - throw new System.InvalidOperationException(SR.Format(SR.TokenizerHelperEmptyToken, _charIndex, _str)); + throw new InvalidOperationException(SR.Format(SR.TokenizerHelperEmptyToken, _charIndex, _str)); } return true; } - // helper to move the _charIndex to the next token or to the end of the string + /// + /// Helper function to move the _charIndex to the next token or to the end of the string. + /// + /// + /// private void ScanToNextToken(char separator) { // if already at end of the string don't bother @@ -254,10 +233,9 @@ private void ScanToNextToken(char separator) // check that the currentChar is a space or the separator. If not // we have an error. this can happen in the quote case // that the char after the quotes string isn't a char. - if (!(currentChar == separator) && - !Char.IsWhiteSpace(currentChar)) + if (!(char.IsWhiteSpace(currentChar) || (currentChar == separator))) { - throw new System.InvalidOperationException(SR.Format(SR.TokenizerHelperExtraDataEncountered, _charIndex, _str)); + throw new InvalidOperationException(SR.Format(SR.TokenizerHelperExtraDataEncountered, _charIndex, _str)); } // loop until hit a character that isn't @@ -275,10 +253,10 @@ private void ScanToNextToken(char separator) if (argSepCount > 1) { - throw new System.InvalidOperationException(SR.Format(SR.TokenizerHelperEmptyToken, _charIndex, _str)); + throw new InvalidOperationException(SR.Format(SR.TokenizerHelperEmptyToken, _charIndex, _str)); } } - else if (Char.IsWhiteSpace(currentChar)) + else if (char.IsWhiteSpace(currentChar)) { ++_charIndex; } @@ -294,7 +272,7 @@ private void ScanToNextToken(char separator) if (argSepCount > 0 && _charIndex >= _strLen) { - throw new System.InvalidOperationException(SR.Format(SR.TokenizerHelperEmptyToken, _charIndex, _str)); + throw new InvalidOperationException(SR.Format(SR.TokenizerHelperEmptyToken, _charIndex, _str)); } } } @@ -310,7 +288,7 @@ internal static char GetNumericListSeparator(IFormatProvider provider) // this method returns the current culture's NumberFormatInfo. NumberFormatInfo numberFormat = NumberFormatInfo.GetInstance(provider); - Debug.Assert(null != numberFormat); + Debug.Assert(numberFormat != null); // Is the decimal separator is the same as the list separator? // If so, we use the ";". @@ -330,13 +308,17 @@ internal bool FoundSeparator } } - private char _quoteChar; - private char _argSeparator; - private string _str; - private int _strLen; + // Readonly fields + private readonly char _quoteChar; + private readonly char _argSeparator; + private readonly string _str; + private readonly int _strLen; + + // State fields private int _charIndex; + private bool _foundSeparator; + internal int _currentTokenIndex; internal int _currentTokenLength; - private bool _foundSeparator; } } diff --git a/src/Microsoft.DotNet.Wpf/src/Shared/MS/Internal/ValueTokenizerHelper.cs b/src/Microsoft.DotNet.Wpf/src/Shared/MS/Internal/ValueTokenizerHelper.cs new file mode 100644 index 00000000000..d2e235937cc --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/Shared/MS/Internal/ValueTokenizerHelper.cs @@ -0,0 +1,312 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Globalization; + +namespace MS.Internal; + +/// +/// Represents a implementation of operating over . +/// +internal ref struct ValueTokenizerHelper +{ + /// + /// Constructor for which accepts an . + /// If the is , we use the thread's info. + /// We will use ',' as the list separator, unless it's the same as the decimal separator. + /// If it *is*, then we can't determine if, say, "23,5" is one number or two. In this case, we will use ";" as the separator. + /// + /// The string which will be tokenized. + /// The which controls this tokenization. + internal ValueTokenizerHelper(ReadOnlySpan input, IFormatProvider formatProvider) : this(input, '\'', GetNumericListSeparator(formatProvider)) { } + + /// + /// Initialize the with the string to tokenize, + /// the char which represents quotes and the list separator. + /// + /// The string to tokenize. + /// The quote char. + /// The list separator. + internal ValueTokenizerHelper(ReadOnlySpan input, char quoteChar, char separator) + { + _input = input; + _currentTokenIndex = -1; + _quoteChar = quoteChar; + _argSeparator = separator; + + // immediately forward past any whitespace so + // NextToken() logic always starts on the first + // character of the next token. + while (_charIndex < _input.Length) + { + if (!char.IsWhiteSpace(_input[_charIndex])) + break; + + ++_charIndex; + } + } + + /// + /// Returns the next available token or if there's none ready. + /// + /// A slice of the next token or . + internal readonly ReadOnlySpan GetCurrentToken() + { + // If there's no current token, return an empty span + if (_currentTokenIndex < 0) + { + return ReadOnlySpan.Empty; + } + + return _input.Slice(_currentTokenIndex, _currentTokenLength); + } + + /// + /// Throws an exception if there is any non-whitespace left un-parsed. + /// + internal readonly void LastTokenRequired() + { + if (_charIndex != _input.Length) + { + throw new InvalidOperationException(SR.Format(SR.TokenizerHelperExtraDataEncountered, _charIndex, _input.ToString())); + } + } + + /// + /// Advances to the next token. + /// + /// if next token was found, if at end of string. + internal bool NextToken() + { + return NextToken(false); + } + + /// + /// Advances to the next token, throwing an exception if not present. + /// + /// A slice of the next next token. + internal ReadOnlySpan NextTokenRequired() + { + if (!NextToken(false)) + { + throw new InvalidOperationException(SR.Format(SR.TokenizerHelperPrematureStringTermination, _input.ToString())); + } + + return GetCurrentToken(); + } + + /// + /// Advances to the next token, throwing an exception if not present. + /// + /// A slice of the next next token. + internal ReadOnlySpan NextTokenRequired(bool allowQuotedToken) + { + if (!NextToken(allowQuotedToken)) + { + throw new InvalidOperationException(SR.Format(SR.TokenizerHelperPrematureStringTermination, _input.ToString())); + } + + return GetCurrentToken(); + } + + /// + /// Advances to the next token. + /// + /// if next token was found, if at end of string. + internal bool NextToken(bool allowQuotedToken) + { + // use the currently-set separator character. + return NextToken(allowQuotedToken, _argSeparator); + } + + /// + /// Advances to the next token. A separator character can be specified which overrides the one previously set. + /// + /// if next token was found, if at end of string. + internal bool NextToken(bool allowQuotedToken, char separator) + { + _currentTokenIndex = -1; // reset the currentTokenIndex + _foundSeparator = false; // reset + + // If we're at end of the string, just return false. + if (_charIndex >= _input.Length) + { + return false; + } + + char currentChar = _input[_charIndex]; + + Debug.Assert(!char.IsWhiteSpace(currentChar), "Token started on Whitespace"); + + // setup the quoteCount + int quoteCount = 0; + + // If we are allowing a quoted token and this token begins with a quote, + // set up the quote count and skip the initial quote + if (allowQuotedToken && _quoteChar == currentChar) + { + quoteCount++; // increment quote count + ++_charIndex; // move to next character + } + + int newTokenIndex = _charIndex; + int newTokenLength = 0; + + // loop until hit end of string or hit a , or whitespace + // if at end of string ust return false. + while (_charIndex < _input.Length) + { + currentChar = _input[_charIndex]; + + // if have a QuoteCount and this is a quote + // decrement the quoteCount + if (quoteCount > 0) + { + // if anything but a quoteChar we move on + if (_quoteChar == currentChar) + { + --quoteCount; + + // if at zero which it always should for now + // break out of the loop + if (quoteCount == 0) + { + ++_charIndex; // move past the quote + break; + } + } + } + else if (char.IsWhiteSpace(currentChar) || (currentChar == separator)) + { + if (currentChar == separator) + { + _foundSeparator = true; + } + break; + } + + ++_charIndex; + ++newTokenLength; + } + + // if quoteCount isn't zero we hit the end of the string + // before the ending quote + if (quoteCount > 0) + { + throw new InvalidOperationException(SR.Format(SR.TokenizerHelperMissingEndQuote, _input.ToString())); + } + + ScanToNextToken(separator); // move so at the start of the nextToken for next call + + // finally made it, update the _currentToken values + _currentTokenIndex = newTokenIndex; + _currentTokenLength = newTokenLength; + + if (_currentTokenLength < 1) + { + throw new InvalidOperationException(SR.Format(SR.TokenizerHelperEmptyToken, _charIndex, _input.ToString())); + } + + return true; + } + + /// + /// Helper function to move the _charIndex to the next token or to the end of the string. + /// + /// + /// + private void ScanToNextToken(char separator) + { + // if already at end of the string don't bother + if (_charIndex < _input.Length) + { + char currentChar = _input[_charIndex]; + + // check that the currentChar is a space or the separator. If not + // we have an error. this can happen in the quote case + // that the char after the quotes string isn't a char. + if (!(char.IsWhiteSpace(currentChar) || (currentChar == separator))) + { + throw new InvalidOperationException(SR.Format(SR.TokenizerHelperExtraDataEncountered, _charIndex, _input.ToString())); + } + + // loop until hit a character that isn't + // an argument separator or whitespace. + int argSepCount = 0; + while (_charIndex < _input.Length) + { + currentChar = _input[_charIndex]; + + if (currentChar == separator) + { + _foundSeparator = true; + ++argSepCount; + _charIndex++; + + if (argSepCount > 1) + { + throw new InvalidOperationException(SR.Format(SR.TokenizerHelperEmptyToken, _charIndex, _input.ToString())); + } + } + else if (char.IsWhiteSpace(currentChar)) + { + ++_charIndex; + } + else + { + break; + } + } + + // if there was a separatorChar then we shouldn't be + // at the end of string or means there was a separator + // but there isn't an arg + + if (argSepCount > 0 && _charIndex >= _input.Length) + { + throw new InvalidOperationException(SR.Format(SR.TokenizerHelperEmptyToken, _charIndex, _input.ToString())); + } + } + } + + // Helper to get the numeric list separator for a given IFormatProvider. + // Separator is a comma [,] if the decimal separator is not a comma, or a semicolon [;] otherwise. + internal static char GetNumericListSeparator(IFormatProvider provider) + { + char numericSeparator = ','; + + // Get the NumberFormatInfo out of the provider, if possible + // If the IFormatProvider doesn't not contain a NumberFormatInfo, then + // this method returns the current culture's NumberFormatInfo. + NumberFormatInfo numberFormat = NumberFormatInfo.GetInstance(provider); + + Debug.Assert(numberFormat != null); + + // Is the decimal separator is the same as the list separator? + // If so, we use the ";". + if ((numberFormat.NumberDecimalSeparator.Length > 0) && (numericSeparator == numberFormat.NumberDecimalSeparator[0])) + { + numericSeparator = ';'; + } + + return numericSeparator; + } + + internal readonly bool FoundSeparator + { + get + { + return _foundSeparator; + } + } + + private readonly char _quoteChar; + private readonly char _argSeparator; + private readonly ReadOnlySpan _input; + + private int _charIndex; + private bool _foundSeparator; + + internal int _currentTokenIndex; + internal int _currentTokenLength; +} diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Generated/Int32Rect.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Generated/Int32Rect.cs index 1855f9172f9..29918ca498f 100644 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Generated/Int32Rect.cs +++ b/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Generated/Int32Rect.cs @@ -162,29 +162,29 @@ public static Int32Rect Parse(string source) { IFormatProvider formatProvider = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; - TokenizerHelper th = new TokenizerHelper(source, formatProvider); + ValueTokenizerHelper tokenizer = new(source, formatProvider); Int32Rect value; - String firstToken = th.NextTokenRequired(); + ReadOnlySpan firstToken = tokenizer.NextTokenRequired(); // The token will already have had whitespace trimmed so we can do a // simple string compare. - if (firstToken == "Empty") + if (firstToken.Equals("Empty", StringComparison.Ordinal)) { value = Empty; } else { value = new Int32Rect( - Convert.ToInt32(firstToken, formatProvider), - Convert.ToInt32(th.NextTokenRequired(), formatProvider), - Convert.ToInt32(th.NextTokenRequired(), formatProvider), - Convert.ToInt32(th.NextTokenRequired(), formatProvider)); + Int32.Parse(firstToken, formatProvider), + Int32.Parse(tokenizer.NextTokenRequired(), formatProvider), + Int32.Parse(tokenizer.NextTokenRequired(), formatProvider), + Int32.Parse(tokenizer.NextTokenRequired(), formatProvider)); } // There should be no more tokens in this string. - th.LastTokenRequired(); + tokenizer.LastTokenRequired(); return value; } diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Generated/Point.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Generated/Point.cs index 9fe73b62a6f..ff7bcc9cb5f 100644 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Generated/Point.cs +++ b/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Generated/Point.cs @@ -142,18 +142,18 @@ public static Point Parse(string source) { IFormatProvider formatProvider = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; - TokenizerHelper th = new TokenizerHelper(source, formatProvider); + ValueTokenizerHelper tokenizer = new(source, formatProvider); Point value; - String firstToken = th.NextTokenRequired(); + ReadOnlySpan firstToken = tokenizer.NextTokenRequired(); value = new Point( - Convert.ToDouble(firstToken, formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider)); + double.Parse(firstToken, formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider)); // There should be no more tokens in this string. - th.LastTokenRequired(); + tokenizer.LastTokenRequired(); return value; } diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Generated/Rect.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Generated/Rect.cs index 69e2c18dc1d..fd7333ab28b 100644 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Generated/Rect.cs +++ b/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Generated/Rect.cs @@ -162,29 +162,29 @@ public static Rect Parse(string source) { IFormatProvider formatProvider = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; - TokenizerHelper th = new TokenizerHelper(source, formatProvider); + ValueTokenizerHelper tokenizer = new(source, formatProvider); Rect value; - String firstToken = th.NextTokenRequired(); + ReadOnlySpan firstToken = tokenizer.NextTokenRequired(); // The token will already have had whitespace trimmed so we can do a // simple string compare. - if (firstToken == "Empty") + if (firstToken.Equals("Empty", StringComparison.Ordinal)) { value = Empty; } else { value = new Rect( - Convert.ToDouble(firstToken, formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider)); + double.Parse(firstToken, formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider)); } // There should be no more tokens in this string. - th.LastTokenRequired(); + tokenizer.LastTokenRequired(); return value; } diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Generated/Size.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Generated/Size.cs index 01fc36c0936..b336fe8991f 100644 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Generated/Size.cs +++ b/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Generated/Size.cs @@ -156,27 +156,27 @@ public static Size Parse(string source) { IFormatProvider formatProvider = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; - TokenizerHelper th = new TokenizerHelper(source, formatProvider); + ValueTokenizerHelper tokenizer = new(source, formatProvider); Size value; - String firstToken = th.NextTokenRequired(); + ReadOnlySpan firstToken = tokenizer.NextTokenRequired(); // The token will already have had whitespace trimmed so we can do a // simple string compare. - if (firstToken == "Empty") + if (firstToken.Equals("Empty", StringComparison.Ordinal)) { value = Empty; } else { value = new Size( - Convert.ToDouble(firstToken, formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider)); + double.Parse(firstToken, formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider)); } // There should be no more tokens in this string. - th.LastTokenRequired(); + tokenizer.LastTokenRequired(); return value; } diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Generated/Vector.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Generated/Vector.cs index 15452bf480d..ff98d3c11cb 100644 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Generated/Vector.cs +++ b/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Generated/Vector.cs @@ -142,18 +142,18 @@ public static Vector Parse(string source) { IFormatProvider formatProvider = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; - TokenizerHelper th = new TokenizerHelper(source, formatProvider); + ValueTokenizerHelper tokenizer = new(source, formatProvider); Vector value; - String firstToken = th.NextTokenRequired(); + ReadOnlySpan firstToken = tokenizer.NextTokenRequired(); value = new Vector( - Convert.ToDouble(firstToken, formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider)); + double.Parse(firstToken, formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider)); // There should be no more tokens in this string. - th.LastTokenRequired(); + tokenizer.LastTokenRequired(); return value; } diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Media/Generated/Matrix.cs b/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Media/Generated/Matrix.cs index 5d1259f6510..b3e2ac161c2 100644 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Media/Generated/Matrix.cs +++ b/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Media/Generated/Matrix.cs @@ -175,31 +175,31 @@ public static Matrix Parse(string source) { IFormatProvider formatProvider = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; - TokenizerHelper th = new TokenizerHelper(source, formatProvider); + ValueTokenizerHelper tokenizer = new(source, formatProvider); Matrix value; - String firstToken = th.NextTokenRequired(); + ReadOnlySpan firstToken = tokenizer.NextTokenRequired(); // The token will already have had whitespace trimmed so we can do a // simple string compare. - if (firstToken == "Identity") + if (firstToken.Equals("Identity", StringComparison.Ordinal)) { value = Identity; } else { value = new Matrix( - Convert.ToDouble(firstToken, formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider), - Convert.ToDouble(th.NextTokenRequired(), formatProvider)); + double.Parse(firstToken, formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider), + double.Parse(tokenizer.NextTokenRequired(), formatProvider)); } // There should be no more tokens in this string. - th.LastTokenRequired(); + tokenizer.LastTokenRequired(); return value; } diff --git a/src/Microsoft.DotNet.Wpf/src/WindowsBase/WindowsBase.csproj b/src/Microsoft.DotNet.Wpf/src/WindowsBase/WindowsBase.csproj index 38aa9a81d81..c25f1baea26 100644 --- a/src/Microsoft.DotNet.Wpf/src/WindowsBase/WindowsBase.csproj +++ b/src/Microsoft.DotNet.Wpf/src/WindowsBase/WindowsBase.csproj @@ -43,7 +43,8 @@ - + + diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/codegen/mcg/generators/ManagedResource.cs b/src/Microsoft.DotNet.Wpf/src/WpfGfx/codegen/mcg/generators/ManagedResource.cs index 5c5834f8061..606ae0b82f2 100644 --- a/src/Microsoft.DotNet.Wpf/src/WpfGfx/codegen/mcg/generators/ManagedResource.cs +++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/codegen/mcg/generators/ManagedResource.cs @@ -2820,14 +2820,14 @@ private static string WriteParse(McgResource resource) { parseBody = [[inline]] - TokenizerHelper th = new TokenizerHelper(source, formatProvider); + ValueTokenizerHelper tokenizer = new(source, formatProvider); [[resource.ManagedName]] resource = new [[resource.ManagedName]](); [[resource.CollectionType.ManagedName]] value; - while (th.NextToken()) + while (tokenizer.NextToken()) { - [[WriteParseBody(resource.CollectionType, "th.GetCurrentToken()")]] + [[WriteParseBody(resource.CollectionType, "tokenizer.GetCurrentToken()")]] resource.Add(value); } diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/codegen/mcg/generators/ManagedStruct.cs b/src/Microsoft.DotNet.Wpf/src/WpfGfx/codegen/mcg/generators/ManagedStruct.cs index b7dc23cc0b6..cb7ce4f4a21 100644 --- a/src/Microsoft.DotNet.Wpf/src/WpfGfx/codegen/mcg/generators/ManagedStruct.cs +++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/codegen/mcg/generators/ManagedStruct.cs @@ -477,11 +477,11 @@ internal[[modifiers]] string ConvertToString(string format, IFormatProvider prov /// This method returns a string which will parse an instance of the type referred to /// by McgType. It assumes that there is a variable called "value" to which it can /// assign the value it produces, as well as assuming that there's a TokenizerHelper - /// called "th" available and in the correct state for parsing. If there's ever a need + /// called "tokenizer" available and in the correct state for parsing. If there's ever a need /// to alter these assumptions, we can add parameters to WriteParseBody to control these. /// It assumes that the first token is present in the string referred to by firstToken, - /// (typically a local string var or "th.GetCurrentToken()", and that all subsequent - /// tokens are required. It is left to the caller to call .LastTokenRequired() if it + /// (typically a local string var or "tokenizer.GetCurrentToken()", and that all subsequent + /// tokens are required. It is left to the caller to call .LastTokenRequired() if it /// wished to ensure that there are no trailing tokens. ///
private static string WriteParseBody(McgType type, @@ -510,8 +510,8 @@ private static string WriteParseBody(McgType type, [[Helpers.CodeGenHelpers.WriteFieldStatementsFirstLastWithSeparator( resource.LocalFields, "{parseMethod}(" + firstToken + ", formatProvider)", - "{parseMethod}(th.NextTokenRequired(), formatProvider)", - "{parseMethod}(th.NextTokenRequired(), formatProvider)", + "{parseMethod}(tokenizer.NextTokenRequired(), formatProvider)", + "{parseMethod}(tokenizer.NextTokenRequired(), formatProvider)", ",\n")]]); [[/inline]]; @@ -523,7 +523,7 @@ private static string WriteParseBody(McgType type, [[inline]] // The token will already have had whitespace trimmed so we can do a // simple string compare. - if ([[firstToken]] == "[[resource.EmptyField.Name]]") + if ([[firstToken]].Equals("[[resource.EmptyField.Name]]", StringComparison.Ordinal)) { value = [[resource.EmptyField.Name]]; } @@ -556,16 +556,16 @@ public static [[resource.Name]] Parse(string source) { IFormatProvider formatProvider = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; - TokenizerHelper th = new TokenizerHelper(source, formatProvider); + ValueTokenizerHelper tokenizer = new(source, formatProvider); [[resource.Name]] value; - String firstToken = th.NextTokenRequired(); + ReadOnlySpan firstToken = tokenizer.NextTokenRequired(); [[WriteParseBody(resource, "firstToken")]] // There should be no more tokens in this string. - th.LastTokenRequired(); + tokenizer.LastTokenRequired(); return value; } diff --git a/src/Microsoft.DotNet.Wpf/src/WpfGfx/codegen/mcg/xml/Resource.xml b/src/Microsoft.DotNet.Wpf/src/WpfGfx/codegen/mcg/xml/Resource.xml index 8b9f3569d23..408cd6ee084 100644 --- a/src/Microsoft.DotNet.Wpf/src/WpfGfx/codegen/mcg/xml/Resource.xml +++ b/src/Microsoft.DotNet.Wpf/src/WpfGfx/codegen/mcg/xml/Resource.xml @@ -1638,10 +1638,10 @@ - + - +