Skip to content

Case insensitive unit parsing and conversion. - #584

Merged
angularsen merged 9 commits into
angularsen:masterfrom
TrevorVonSeggern:feature/CaseSensitivity
Jan 27, 2019
Merged

Case insensitive unit parsing and conversion.#584
angularsen merged 9 commits into
angularsen:masterfrom
TrevorVonSeggern:feature/CaseSensitivity

Conversation

@TrevorVonSeggern

Copy link
Copy Markdown
Contributor

The purpose of this is to allow this library to allow for "year" and "Year" in the unit parser and UnitConverter without adding different casing to every abbreviation in the unit definitions.

@angularsenangularsen left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! A few comments for you to consider.

Comment threadUnitsNet.Tests/UnitParserTests.cs
Comment threadUnitsNet/CustomCode/UnitValueAbbreviationLookup.cs Outdated
Comment threadUnitsNet/UnitConverter.cs Outdated
Comment threadUnitsNet/UnitConverter.cs Outdated
Comment threadUnitsNet/UnitConverter.cs
Comment threadUnitsNet/CustomCode/UnitValueAbbreviationLookup.cs Outdated

@angularsenangularsen left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feedback on latest commit.

Comment threadUnitsNet.Tests/UnitParserTests.cs
Comment threadUnitsNet/UnitConverter.cs Outdated
private static readonly string UnitTypeNamespace = typeof(LengthUnit).Namespace;
private static readonly Assembly UnitsNetAssembly = typeof(Length).GetAssembly();

private static readonly List<Type> QuantityTypes = UnitsNetAssembly.GetTypes()

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we are targeting .NET 4.0 we probably can't use IReadOnlyList<T> as I originally advised, I believe that came in .NET 4.5. I would recommend using an array and .ToArray() then, just to make it more clear that this is not supposed to be manipulated.


if(!Enum.IsDefined(unitType, unitName))
var eNames = Enum.GetNames(unitType);
unitName = eNames.FirstOrDefault(x => x.Equals(unitName, StringComparison.OrdinalIgnoreCase));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably use Enum.TryParse which includes a bool parameter to specify ignoring case. See here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would also prefer this method, but I can't use that here without using reflection, which I was trying to avoid. The try parse method you linked takes a generic type argument, which means that the type has to be known at compile type. We have a Type parameter known only at run time. Is there another TryParse that you know of that takes the enum type "Type" as parameter?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enum.TryParse<T>(string, bool, out T) exists, but I suspect since we target .NET 4.0 is why we can't use it.

@angularsenangularsen left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some more comments.

Comment threadUnitsNet.Tests/UnitConverterTest.cs Outdated
}

[Fact]
public void ConvertByName__UnitTypeCaseInsensitive()

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the double underscore intentional here and above?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unintentional.


internal List<int> GetUnitsForAbbreviation(string abbreviation)
{
abbreviation = abbreviation.ToLower();

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would make this a separate variable lowercaseAbbreviation to make it more clear. You can choose the name, but make the variable lower in the Add method below the same name for consistency.


internal void Add(int unit, string abbreviation, bool setAsDefault = false)
{
// abbreviation = abbreviation.ToLower();

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove commented code.

Comment threadUnitsNet/UnitConverter.cs Outdated
private static bool TryGetUnitType(string quantityName, out Type unitType)
{
string unitTypeName = $"{UnitTypeNamespace}.{quantityName}Unit";
quantityName += "Unit";

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make it a variable, f.ex. unitTypeName. Also I think we can keep the example comment, but modify to // Example: "LengthUnit". I think this is helpful when reading the code.

@angularsenangularsen left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found some things, but I added fixes to the PR for them. Looks good to me now.

Comment threadUnitsNet/UnitConverter.cs Outdated
private static bool TryGetUnitType(string quantityName, out Type unitType)
{
quantityName += "Unit";
var quantityTypeName = quantityName += "Unit"; // ex. LengthUnit

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be named unitTypeName, quantity would be Length.

Edit: I fixed it in the PR.


if(!Enum.IsDefined(unitType, unitName))
var eNames = Enum.GetNames(unitType);
unitName = eNames.FirstOrDefault(x => x.Equals(unitName, StringComparison.OrdinalIgnoreCase));

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enum.TryParse<T>(string, bool, out T) exists, but I suspect since we target .NET 4.0 is why we can't use it.

private static readonly string UnitTypeNamespace = typeof(LengthUnit).Namespace;
private static readonly Assembly UnitsNetAssembly = typeof(Length).GetAssembly();

private static readonly Type[] QuantityTypes = UnitsNetAssembly.GetTypes()

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These include a lot more types than just the quantity structs and the unit enums.
I'm adding a fix.

@angularsen

Copy link
Copy Markdown
Owner

Build is failing on WRC target with my latest changes, fixing.

@angularsen

Copy link
Copy Markdown
Owner

Finally, good to go. Merging!

@angularsen
angularsen merged commit 04c78c0 into angularsen:masterJan 27, 2019
@angularsen

Copy link
Copy Markdown
Owner

Woops, found a bug. We lowercase the prefixes so we can no longer distinguish milli from mega :-)

image

As a result, Pressure.Parse("3 Mbar") fails, because there are two abbreviations it matches.
I'm looking into if there is a quick fix. Creating a new issue #590.

@angularsen

Copy link
Copy Markdown
Owner

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@TrevorVonSeggern@angularsen@tmilnthorp