Skip to content

Commit

Permalink
✨Make QuantityParser public (#1264)
Browse files Browse the repository at this point in the history
Fixes #1263 

This was initially made internal while we matured its design, but it has
been stable for a long time now and ready for external use. Making it
public makes it possible to parse custom units, as described in the
wiki.

### Changes
- Make `QuantityParser` and its `Parse`, `TryParse` methods public
- Add xmldoc
  • Loading branch information
angularsen authored Jun 16, 2023
1 parent aa1a999 commit ed1d35d
Showing 1 changed file with 61 additions and 8 deletions.
69 changes: 61 additions & 8 deletions UnitsNet/CustomCode/QuantityParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,24 @@
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using UnitsNet.Units;

// ReSharper disable once CheckNamespace
namespace UnitsNet
{

internal delegate TQuantity QuantityFromDelegate<out TQuantity, in TUnitType>(QuantityValue value, TUnitType fromUnit)
/// <summary>
/// A method signature for creating a quantity given a numeric value and a strongly typed unit, for example 1.0 and <see cref="LengthUnit.Meter"/>.
/// </summary>
/// <typeparam name="TQuantity">The type of quantity to create, such as <see cref="Length"/>.</typeparam>
/// <typeparam name="TUnitType">The type of unit enum that belongs to this quantity, such as <see cref="LengthUnit"/> for <see cref="Length"/>.</typeparam>
public delegate TQuantity QuantityFromDelegate<out TQuantity, in TUnitType>(QuantityValue value, TUnitType fromUnit)
where TQuantity : IQuantity
where TUnitType : Enum;

internal class QuantityParser
/// <summary>
/// Parses quantities from strings, such as "1.2 kg" to <see cref="Length"/> or "100 cm" to <see cref="Mass"/>.
/// </summary>
public class QuantityParser
{
/// <summary>
/// Allow integer, floating point or exponential number formats.
Expand All @@ -26,9 +34,17 @@ internal class QuantityParser
private readonly UnitAbbreviationsCache _unitAbbreviationsCache;
private readonly UnitParser _unitParser;

/// <summary>
/// The default instance of <see cref="QuantityParser"/>, which uses <see cref="UnitAbbreviationsCache.Default"/> unit abbreviations.
/// </summary>
public static QuantityParser Default { get; }

public QuantityParser(UnitAbbreviationsCache? unitAbbreviationsCache)
/// <summary>
/// Creates an instance of <see cref="QuantityParser"/>, optionally specifying an <see cref="UnitAbbreviationsCache"/>
/// with unit abbreviations to use when parsing.
/// </summary>
/// <param name="unitAbbreviationsCache">(Optional) The unit abbreviations cache, or specify <c>null</c> to use <see cref="UnitAbbreviationsCache.Default"/>.</param>
public QuantityParser(UnitAbbreviationsCache? unitAbbreviationsCache = null)
{
_unitAbbreviationsCache = unitAbbreviationsCache ?? UnitAbbreviationsCache.Default;
_unitParser = new UnitParser(_unitAbbreviationsCache);
Expand All @@ -39,8 +55,19 @@ static QuantityParser()
Default = new QuantityParser(UnitAbbreviationsCache.Default);
}

/// <summary>
/// Parses a quantity from a string, such as "1.2 kg" to <see cref="Length"/> or "100 cm" to <see cref="Mass"/>.
/// </summary>
/// <param name="str">The string to parse, such as "1.2 kg".</param>
/// <param name="formatProvider">The culture for looking up localized unit abbreviations for a language, and for parsing the number formatted in this culture. Defaults to <see cref="CultureInfo.CurrentCulture"/>.</param>
/// <param name="fromDelegate">A function to create a quantity given a numeric value and a unit enum value.</param>
/// <typeparam name="TQuantity">The type of quantity to create, such as <see cref="Length"/>.</typeparam>
/// <typeparam name="TUnitType">The type of unit enum that belongs to this quantity, such as <see cref="LengthUnit"/> for <see cref="Length"/>.</typeparam>
/// <returns>The parsed quantity if successful.</returns>
/// <exception cref="ArgumentNullException">The string was null.</exception>
/// <exception cref="FormatException">Failed to parse quantity.</exception>
[SuppressMessage("ReSharper", "UseStringInterpolation")]
internal TQuantity Parse<TQuantity, TUnitType>(string str,
public TQuantity Parse<TQuantity, TUnitType>(string str,
IFormatProvider? formatProvider,
QuantityFromDelegate<TQuantity, TUnitType> fromDelegate)
where TQuantity : IQuantity
Expand All @@ -61,8 +88,20 @@ internal TQuantity Parse<TQuantity, TUnitType>(string str,
return ParseWithRegex(valueString, unitString, fromDelegate, formatProvider);
}

/// <summary>
/// Tries to parse a quantity from a string, such as "1.2 kg" to <see cref="Length"/> or "100 cm" to <see cref="Mass"/>.
/// </summary>
/// <param name="str">The string to parse, such as "1.2 kg".</param>
/// <param name="formatProvider">The culture for looking up localized unit abbreviations for a language, and for parsing the number formatted in this culture. Defaults to <see cref="CultureInfo.CurrentCulture"/>.</param>
/// <param name="fromDelegate">A function to create a quantity given a numeric value and a unit enum value.</param>
/// <param name="result">The parsed quantity if successful, otherwise null.</param>
/// <typeparam name="TQuantity">The type of quantity to create, such as <see cref="Length"/>.</typeparam>
/// <typeparam name="TUnitType">The type of unit enum that belongs to this quantity, such as <see cref="LengthUnit"/> for <see cref="Length"/>.</typeparam>
/// <returns>True if successful.</returns>
/// <exception cref="ArgumentNullException">The string was null.</exception>
/// <exception cref="FormatException">Failed to parse quantity.</exception>
[SuppressMessage("ReSharper", "UseStringInterpolation")]
internal bool TryParse<TQuantity, TUnitType>(string? str,
public bool TryParse<TQuantity, TUnitType>(string? str,
IFormatProvider? formatProvider,
QuantityFromDelegate<TQuantity, TUnitType> fromDelegate,
out TQuantity result)
Expand All @@ -81,10 +120,24 @@ internal bool TryParse<TQuantity, TUnitType>(string? str,
}

/// <summary>
/// Workaround for C# not allowing to pass on 'out' param from type Length to IQuantity, even though the are compatible.
/// Tries to parse a quantity from a string, such as "1.2 kg" to <see cref="Length"/> or "100 cm" to <see cref="Mass"/>.
/// </summary>
/// <remarks>
/// Similar to <see cref="TryParse{TQuantity,TUnitType}(string?,System.IFormatProvider?,UnitsNet.QuantityFromDelegate{TQuantity,TUnitType},out TQuantity)"/>,
/// but returns <see cref="IQuantity"/> instead. This is workaround for C# not allowing to pass on 'out' param from type Length to IQuantity,
/// even though the are compatible.
/// </remarks>
/// <param name="str">The string to parse, such as "1.2 kg".</param>
/// <param name="formatProvider">The culture for looking up localized unit abbreviations for a language, and for parsing the number formatted in this culture. Defaults to <see cref="CultureInfo.CurrentCulture"/>.</param>
/// <param name="fromDelegate">A function to create a quantity given a numeric value and a unit enum value.</param>
/// <param name="result">The parsed quantity if successful, otherwise null.</param>
/// <typeparam name="TQuantity">The type of quantity to create, such as <see cref="Length"/>.</typeparam>
/// <typeparam name="TUnitType">The type of unit enum that belongs to this quantity, such as <see cref="LengthUnit"/> for <see cref="Length"/>.</typeparam>
/// <returns>True if successful.</returns>
/// <exception cref="ArgumentNullException">The string was null.</exception>
/// <exception cref="FormatException">Failed to parse quantity.</exception>
[SuppressMessage("ReSharper", "UseStringInterpolation")]
internal bool TryParse<TQuantity, TUnitType>(string str,
public bool TryParse<TQuantity, TUnitType>(string str,
IFormatProvider? formatProvider,
QuantityFromDelegate<TQuantity, TUnitType> fromDelegate,
out IQuantity? result)
Expand Down

0 comments on commit ed1d35d

Please sign in to comment.