-
Notifications
You must be signed in to change notification settings - Fork 404
QuantityValue implemented as a fractional number 🐲 #1544
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- IQuantity interfaces optimized (some methods refactored as extensions) - QuantityInfo/UnitInfo hierachy re-implemented (same properties, different constructors) - QuantityInfoLookup is now public - UntAbbreviationsCache, UnitParser, QuantityParser optimized - UnitConverter: re-implemented (multiple versions) - removed the IConvertible interface - updated the JsonNet converters - introducing the SystemTextJson project - added a new UnitsNetConfiguration to the Samples project showcasing the new configuration options - many more tests and benchmarks (perhaps too many)
@angularsen Clearly, I don't expect this to get merged in the Gitty up! fashion, but at least we have the whole picture, with sources that I can reference.
If you want, send me an e-mail, we could do a quick walk-through / discussion.
...lection constructors with IEnumerable - `UnitAbbreviationsCacheInitializationBenchmarks`: replaced some obsolete usages
100k lines removed, 100k lines added 🙈
100k lines removed, 100k lines added 🙈
I tried to create this PR twice before (many months ago), while the changes to the unit definitions were still not merged- and the web interface was giving me an error when trying to browse the files changed.. Something like "Too many files to display" 😄
Ok, I'm not going to get through a review of this many files anytime soon.
Maybe we should have a screen sharing session and go through it together. I may have some time this weekend, what about you? What timezone are you in?
On the surface though, it seems like this could be split up into chunks. I know it's tedious and extra work, but it will be way faster to review. Do you see any chunks of changes to easily split off into separate PRs?
Ok, I'm not going to get through a review of this many files anytime soon. Maybe we should have a screen sharing session and go through it together. I may have some time this weekend, what about you? What timezone are you in?
Sofia (GMT+3), but time zones are not relevant to my sleep schedule - so basically any time you want.
On the surface though, it seems like this could be split up into chunks. I know it's tedious and extra work, but it will be way faster to review. Do you see any chunks of changes to easily split off into separate PRs?
Yes, I do have some ideas:
-
UnitAbbreviationsCacheand theUnitParsershould be more or less free of changes onceUnitAbbreviationsCache.CreateEmptyshould use the defaultQuantityInfoLookup#1548 is merged - I plan to remove the
IConvertibleinterface tonight (lots of red points there) - The
QuantityParserhas just a few minor changes which I was going to try to push as well (other than that it's mostly justdoublechanging toQuantityValue) -
QuantityFormatter- there was an issue that I created earlier that should (mostly) solve the differences - Refactoring the
QuantityInfocan theoretically be done without theConversionExpressions (which would open the way for the changes to theIQuantityinterface and some of the extension methods). -
UnitParser: introduce two new method:GetUnitFromAbbreviationandTryGetUnitFromAbbreviationreturning aUnitInfo(which could be used for constructing an instance of the quantity) - Introduce the changes to the
IQuantityinterface and some of the extension methods - Move the exceptions in their own folder and replace the usages of the
NotImplementedExceptionwith the appropriateUnitNotFoundException - Update the
UnitTestBaseClassGenerator- I've refactored theParse/TryParsetests (completing the test coverage) - having a look at the diff on theMassTestsBase.g.cs, it looks like these account for about half of all diffs in the PR 😄 - Make the
QuantityInfoLookuppublic: apart from the extra constructors, there doesn't appear to be any other differences- and I don't see any reason to keep it internal - Introduce the
CodeGen/Helpers/ExpressionEvaluationHelpers.cs+CodeGen/Helpers/ExpressionAnalyzerand replace the unit conversion expressions such as(_value / 1e3) * 1e-2d)with the simplified expression (unless we actually plan to use the the rest of this PR- this would probably be an overkill). - The
JsonQuantityConverterstuff fromSystemTextcould theoretically come with it'sdoubleversions first (but we do need to have a discussion about it)
Hopefully by the time we get to 5) you'd be up to speed (and fed up with PRs) and we can turn back to reviewing / working on the rest of it as a whole 😄
Ok, sounds good. Just send PRs my way and I'll try to get to them. I have a little bit of extra time this weekend.
...ions into their own folder
- UnitAbbreviationsCache: removing the obsolete overload - adding a few more tests
This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.
This PR was automatically closed due to inactivity.
...ramework (net8.0) with 9.0 on the QuantityInfoBenchmarks
...OfType / IQuantityInstanceInfo)
@angularsen I've synced the changes from upstream, however instead of bringing down the diffs, this has added another ~200 file changes (the new NumberExtensions).
I've updated the task list (completing the IQuantity interface refactoring). The next task on the list is
Introduce the CodeGen/Helpers/ExpressionEvaluationHelpers.cs + CodeGen/Helpers/ExpressionAnalyzer and replace the unit conversion expressions such as (_value / 1e3) * 1e-2d) with the simplified expression (unless we actually plan to use the the rest of this PR- this would probably be an overkill).
... but that can only start after I've had a confirmation, that we're moving towards replacing the double (in v6).
@lipchev I really like the concept of the decimal fractions, it solves equality issues and precision, and if I recall correctly it remains fairly backwards compatible.
I want to say let's go, but if you could please help me out and give a short summary for a couple of things that would help a lot as I don't recall and I'm pressed for time.
- How does it affect performance? CPU time on creating a quantity, converting units and ToString are perhaps the big ones. Allocations are also relevant. I don't need full benchmarks, just a top level understanding of are we talking 2x, 10x, 100x orders of magnitude.
- Any significant breaking changes to be aware of?
* How does it affect performance? CPU time on creating a quantity, converting units and ToString are perhaps the big ones. Allocations are also relevant. I don't need full benchmarks, just a top level understanding of are we talking 2x, 10x, 100x orders of magnitude.
I spent a full Sunday back in February creating a comparison chart, but before I could finish up setting up all the sheets, I accidentally executed the build script which erased all of my benchmark results. 😠 I'll attach the file as it is, but the gist is that compared to v5 there should be a significant performance improvement, especially when it comes to the strings.
UnitsNet-Benchmarks.xlsx
The conversions are about the same, or faster (with units other than the BaseUnit). There are no allocations, as long as the Value is represented by a fraction, who's terms are smaller than int.MaxValue.
For example the value 42.24 is represented as 4224 / 100, which when multiplied by 1000 (some Kilo conversion) would become 4224000 / 100 which is still small enough. Note that I intentionally avoid the (possible) reduction, since keeping the original denominator generally makes the additions / subtractions more efficient: for example adding 1.23 to would result in 4224123 / 100 (simply adding the integers in the numerators). So, while dividing 4224000 / 100 by 1000 would revert back to 4224 / 100, doing a bunch of multiplications (without manually calling QuantityValue.Reduce) would sooner or later hit the magical threshold (int.MaxValue) which would trigger the allocation of the uint[]? _bits. From there on, the performance scales linearly with the size of the bits increasing by 1 for every power of int.MaxValue (my PC was still able to do square roots, even after something like 500K digits of precision). Anyway, I've got a ton of benchmarks of the implementation over at the Fractions repo (with loads of pretty charts) - when we factor in the occasional allocations, the raw arithmetic-performance was within the same order of magnitude as the decimal (it was 2x-6x slower back on Jul 1, 2024, and I expect the QuantityValue to be slightly faster).
The initialization is slower but no more than 10x, judging from these benchmarks but that can be reduced by loading a select subset of quantities (I imagine loading just 10 QuantityInfos would still at least 2x faster).
PS The Inverse method is also something like 2x slower (but that's due to the extra logic)...
PS2 Aside for the static benchmarks, I've also observed a visible improvement (in the performance logs) after migrating my code-base, but that's probably due to the improvements to the string handling stuff around the UnitParser, UnitAbbreviations etc. (from v5 to v6).
* Any significant breaking changes to be aware of?
Compared to the v5 the only significant change is that
double value = Mass.Zero.Valueis not alloweddecimal value = Power.Zero.Valueis not allowed
both of these return aQuantityValuewhich does not support the implicit conversion todoubleordecimal:double value = (double)Mass.Zero.Valueis alloweddecimal value = Power.Zero.Value.ToDecimal()is also allowed
While inconvenient, this is the correct way to do it (implicit conversions from, and explicit conversion to any primitive number).
By the way, given that in v5 IQuantity.Value is still defined as QuantityValue (without an explicit cast as far as I remember), this shouldn't be that much of surprise 🤷
Thank you. I'll post some thoughts before reviewing the actual PR code changes.
Excel sheet
Nice overview, here is my read of it:
- Perf improvements for all but ToUnit
- The biggest absolute improvements:
- Parse/TryParse is ~60% faster (49000 to 18000 ns)
- ToString is ~75% faster (700 to 150 ns)
- SI/UnitSystem overloads are 45% faster (200 to 120 ns)
- ToUnit is 60% slower, but in absolute terms negligible (+15 ns)
Normalizing
Regarding not normalizing and running into allocations when crossing int.MaxValue, this is useful to know (new to me) and something worth documenting in v6 release. We'll need to explain the pros/cons of decimal fractions anyway.
There are maybe ways to optimize when to normalize and not? Either way, manual control of normalize is nice for those who care about it.
Initialization
Can't we just lazy initialize the quantities actually used? Not sure how much work that would be.
Breaking changes
Good overview. What are the disadvantages of supporting implicit cast to double and decimal though? It seems really convenient to me.
|
Initial review by Claude. PR Review: QuantityValue as Fractional Number 🐲PR: #1544 OverviewThis is a massive, fundamental rewrite of UnitsNet's core architecture:
Key Changes1. QuantityValue → Fractional Representation
// Internal representation private readonly BigInteger _numerator; private readonly BigInteger? _denominator; // Example: Exact fractions instead of floating-point new QuantityValue(5000, 127) // Exact: 5000/127 for inches Benefits:
2. API Breaking Changes
3. New Features
4. Architecture Improvements
Migration ImpactBreaking Changes ExamplesEvery consumer will need code changes: // ❌ Breaking - no longer compiles double meters = length.Value; double ratio = length1 / length2; var newLength = new Length(5.0, LengthUnit.Meter); void ProcessDistance(double meters) { } ProcessDistance(length.Meters); // ✅ Migration needed QuantityValue meters = length.Value; double metersAsDouble = length.Value.ToDouble(); QuantityValue ratio = length1 / length2; var newLength = new Length(new QuantityValue(5), LengthUnit.Meter); void ProcessDistance(double meters) { } ProcessDistance(length.Meters.ToDouble()); Interface Changes// ❌ Removed from IQuantity double As(Enum unit); double As(UnitKey unitKey); IQuantity ToUnit(Enum unit); IQuantity<T>.ToUnit(UnitSystem unitSystem); // ✅ Now available as extension methods QuantityExtensions.As(this IQuantity quantity, UnitKey unitKey); QuantityExtensions.ToUnit(this IQuantity quantity, UnitKey unitKey); QuantityExtensions.ToUnit<T>(this IQuantity<T> quantity, UnitSystem unitSystem); Serialization CompatibilityGood News 🎉JSON serialization is mostly backwards compatible with the right configuration: // Old format (v5): {"Value":10.0,"Unit":"m"} // New format (v6): {"Value":10,"Unit":"m"} // Deserialize old data with RoundedDouble option: var converter = new AbbreviatedUnitsConverter( new QuantityValueFormatOptions( SerializationFormat: QuantityValueSerializationFormat.DoublePrecision, DeserializationFormat: QuantityValueDeserializationFormat.RoundedDouble )); Length length = JsonConvert.DeserializeObject<Length>(oldJson, converter); // ✅ Can read old JSON! Default Behavior Change
|
On Rider, this was needed to actually run the samples with 'Official' configuration. Only Debug/Release were shown.
This reverts commit 896f765.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Posting review so far, I got down through SystemTextJson.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SystemTextJson is candidate for separate PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Never mind, let's just review and merge everything
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this mean Lenght.Zero would exclude the value in the JSON/XML?
I think I prefer both the value and unit to always be included. Optional values can make sense to omit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My philosophy regarding data DataContractSerializer and the DataContractJsonSerializer is that these are only used/useful in machine-to-machine communications (such as WCF or the GRPC gateway thing, which AFAIK builds up the protos based off the data contracts)- as such I've dropped all constraints regarding the human-readability of the output and prioritized the reduction of the payload size.
The difference isn't huge, but given how bloated the xml output is, and how rarely one (i.e. a person) actually reads it, I figured it wouldn't hurt to shave off a few bytes when possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of scope, but double here seems like it could be renamed to avoid this string replace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we should probably replace it in the UnitRelations.json (marking it as a potential breaking change).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is kinda hard to read, some example code in comments would be helpful
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can remove these comments, and put them in the extension method if not already documented there. Inline the leftUnit also so this becomes more or less a one-liner.
Same for below method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default ctor xmldoc could be more clear about what the defaults are.
Same with QuantityValueFormatOptions, it could also more plainly state the defaults in its xmldoc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit, but should this not be renamed to something like XxxJsonWriterExtensions?
It also has Reader stuff, so maybe suffix XxxJsonExtensions or split into reader/writer files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd use a real high number to avoid having to bump this, but this will soon be a thing of the past.
We must remember to reset this back when merging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm only skimming all the serialization stuff. At first glance I don't see why we have both InterfaceQuantityWithUnitTypeConverter and InterfaceQuantityConverterBase.
It seems InterfaceQuantityWithUnitTypeConverter is unused/untested?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Package release notes can maybe be set to something like initial release.
...rseInvariant Specify invariant culture for Fraction and `int` parsing.
This is typically not a problem with integers, but let's be explicit. Integer parsing is done for quantity string formatting to control number formats, such as `a2` for the 2nd unit abbreviation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another batch of comments.
I got down to: ConversionExpressionTests.cs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update xmldoc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove commmented code or add clear TODO
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very thorough set of tests, I like it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does look a bit weird to have extension method Configure on a collection of UnitDefinition items.
I think it would be better to either create a wrapper type to hold the collection and offer these methods, or convert the extension methods to a named static helper class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I pushed a rename to WithConversionFactorFromBase
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean, I love tests, but holy shit you've produced a lot of tests 🤯
We'll keep them all of course, but yes I do think it's maybe a bit excessive at times 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I had most of these implemented in the Fractions library. As I decided to move them in here, I also implemented the ReadOnlySpan overloads- which made the whole thing explode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either remove commented tests or add clear TODO on how to add them back
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HowMuch is gradually getting cleaner 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we ensuring backwards compatibility for deserializing JSON like {"Value": 1.2, "Unit": 5} elsewhere?
Also, the _bits stuff looks very internal. Is it feasible to have this match the output of SystemTextJson?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The DataContractJsonSerializer is a lost cause- not even microsoft bothers with it any more.
I did try to customize it (trying to preserve the original output) - but there was a bug (I've left a link to the github issues in a comment somewhere) which prevented me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar for xml, what is the plan for backwards compat and migration steps here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I believe there is an example which uses a data-contract-surrogate.
PS I originally tried implementing the IXmlSerializable interface, but then I encountered another bug in the proxy-generation stack (not sure if I left the link to that issue or not).
I saw quite a bit of commented code here and there, so I asked Claude to identify all the commented out parts. Something to consider going over.
PR #1544 - Commented Code Review
PR Title: QuantityValue implemented as a fractional number 🐲
Author: @lipchev
Status: Open
Summary
This review identifies commented-out code in PR #1544 that should either be removed or have TODO comments explaining why it's commented out and what the plan is for uncommenting later.
🔴 High Priority - Remove Immediately
1. QuantitiesSelector.cs - Duplicate Commented Class (112 lines!)
File: UnitsNet/CustomCode/QuantityInfo/Builder/QuantitiesSelector.cs
Lines: 133-244
Issue: Entire duplicate class definition (~112 lines) commented out with no explanation
// /// <summary> // /// Provides functionality to select and configure quantities for use within the UnitsNet library. // /// </summary> // ... [full duplicate class implementation - 112 lines] // }
Recommendation: DELETE - This appears to be an old version of the same class that should have been removed. Git history preserves this for reference if needed.
2. ExpressionEvaluator.cs - "No Longer Necessary" Code
File: CodeGen/Helpers/ExpressionAnalyzer/ExpressionEvaluator.cs
Lines: 278-283
// these are no longer necessary // var expressionEvaluator = new ExpressionEvaluator(parameter, constantExpressions, // new SqrtFunctionEvaluator(), // new PowFunctionEvaluator(), // new SinFunctionEvaluator(), // new AsinFunctionEvaluator()); var expressionEvaluator = new ExpressionEvaluator(parameter, constantExpressions);
Recommendation: DELETE - Explicitly marked as "no longer necessary". Git history preserves the old constructor call pattern.
🟡 Medium Priority - Remove or Add TODO
3. QuantitiesSelector.cs - Unused Property
File: UnitsNet/CustomCode/QuantityInfo/Builder/QuantitiesSelector.cs
Line: 30
// internal Lazy<IEnumerable<QuantityInfo>> QuantitiesSelected { get; }Recommendation: DELETE - No explanation provided; appears to be leftover from refactoring.
4. QuantitiesSelector.cs - ToList() Alternative
File: UnitsNet/CustomCode/QuantityInfo/Builder/QuantitiesSelector.cs
Line: 98
return enumeration; // return enumeration.ToList();
Recommendation: Either:
- DELETE if
ToList()is definitely not needed, OR - ADD TODO:
// TODO: Consider materializing with ToList() if multiple enumerations cause performance issues
5. DynamicQuantityConverter.cs - Old Implementation (2 instances)
File: UnitsNet/CustomCode/QuantityConverters/DynamicQuantityConverter.cs
Line 58:
// TryGetUnitInfo(conversionKey.FromUnitKey with { UnitValue = conversionKey.ToUnitValue }, out UnitInfo? toUnitInfo))Line 347:
// return targetQuantityInfo.Create(conversionFunction.Convert(value), conversionFunction.TargetUnit); return targetQuantityInfo.From(conversionFunction.Convert(value), conversionFunction.TargetUnit.ToUnit<TTargetUnit>());
Recommendation: Either:
- DELETE if old implementations are not needed, OR
- ADD TODO explaining why preserved (e.g., performance comparison, alternative approach)
6. FrozenQuantityConverter.cs - Old Implementation
File: UnitsNet/CustomCode/QuantityConverters/FrozenQuantityConverter.cs
Line: 67
// TryGetUnitInfo(conversionKey.FromUnitKey with { UnitValue = conversionKey.ToUnitValue }, out UnitInfo? toUnitInfo))Recommendation: Same as DynamicQuantityConverter - either DELETE or add TODO with explanation.
7. FractionExtensions.cs - Old Double-Based Approach
File: CodeGen/Helpers/ExpressionAnalyzer/Functions/Math/FractionExtensions.cs
Line: 35-36
// return FromDoubleRounded(System.Math.Pow(x.ToDouble(), power.ToDouble())); return PowRational(x, power);
Recommendation: Either:
- DELETE if
PowRationalis proven stable, OR - ADD TODO:
// TODO: Old double-based approach for reference - remove once PowRational is proven stable in production
✅ Keep (Already Have Adequate Explanation)
ConversionExpression.cs - Inline Documentation
File: UnitsNet/CustomCode/QuantityInfo/Units/ConversionExpression.cs
Lines: 264, 268, 276, 282, 293, 297, 305, 311, 322, 328, 336, 342
These comments show simplified lambda forms that enhance readability. Keep as-is.
// scaleFunction = value => value; // scaleFunction = value => value * coefficient;
UnitsNetSetup.cs - Future Work TODOs
File: UnitsNet/CustomCode/UnitsNetSetup.cs
Lines: 35-38
// TODO see about allowing eager loading // private AbbreviationsCachingMode AbbreviationsCaching { get; set; } = AbbreviationsCachingMode.Lazy; // TODO see about caching the regex associated with the UnitParser // private UnitsCachingMode UnitParserCaching { get; set; } = UnitsCachingMode.Lazy;
Status: ✅ Properly documented future work. Keep as-is.
UnitTestBaseClassGenerator.cs - Documented Limitation
File: CodeGen/Generators/UnitsNetGen/UnitTestBaseClassGenerator.cs
Lines: 1138-1139
// note: it's currently not possible to test this due to the rounding error from (quantity - otherQuantity) // Assert.True(quantity.Equals(otherQuantity, maxTolerance));
Status: ✅ Well-documented limitation. Keep as-is.
MainWindowVM.cs - Sample Code Alternative Approach
File: Samples/UnitConverter.Wpf/UnitConverter.Wpf/MainWindowVM.cs
Lines: 135-136
// note: starting from v6 it is possible to store (and invoke here) a conversion expression // ConvertValueDelegate _convertValueToUnit = UnitsNet.UnitConverter.Default.GetConversionFunction(...); // ToValue = _convertValueToUnit(FromValue);
Status: ✅ Sample/demo code showing users an alternative v6 feature. Keep as-is.
ExpressionEvaluationHelpers.cs - Implicit Constructor Note
File: CodeGen/Helpers/ExpressionEvaluationHelpers.cs
Line: 354
// return $"new ConversionExpression({coefficientTermFormat})"; return coefficientTermFormat; // using the implicit constructor from QuantityValue
Status: ✅ Has explanation, though could be slightly improved:
Optional improvement:
// Old explicit approach: return $"new ConversionExpression({coefficientTermFormat})"; return coefficientTermFormat; // using the implicit constructor from QuantityValue
Summary Statistics
- 🔴 High Priority Deletions: 2 instances (~118 lines)
- 🟡 Medium Priority (Remove or TODO): 7 instances
- ✅ Keep (Adequate documentation): 6 categories of comments
Recommended Actions
- Delete the 112-line duplicate class in
QuantitiesSelector.cs(lines 133-244) - Delete "no longer necessary" code in
ExpressionEvaluator.cs(lines 278-283) - Review the 7 medium-priority items and either:
- Delete if no longer needed, or
- Add clear TODO comments explaining preservation reason
This will remove ~125+ lines of dead code and improve code maintainability.
Uh oh!
There was an error while loading. Please reload this page.
QuantityValueimplemented as a fractional numberIQuantityinterfaces optimized (some methods refactored as extensions)UnitInfo: introduced two new properties:ConversionFromBaseandConversionToBasewhich are used instead of theswitch(Unit)conversionUnitsNetSetup: introduced helper methods for adding external quantities, or re-configuring one or more of the existing onesUntAbbreviationsCache: introduced additional factory methods (using a configuration delegate)UnitParser: introduced additional factory methods (using a configuration delegate)UnitConverter: re-implemented (multiple versions)Inverserelationship mapping implemented as a type of implicit conversion