Skip to content

Conversation

@lipchev
Copy link
Collaborator

@lipchev lipchev commented Aug 16, 2025

  • replaced the ToUnit(UnitSystem) overload from the IQuantity<TUnit> interface with an extension method ([Obsolete])
  • renamed the ToUnitUntyped extension back to ToUnit and made it [Obsolete]
  • replaced the generated UnitSystem tests for the IQuantity / IQuantity<TUnit> with a single set of tests in the IQauntityTests

lipchev and others added 7 commits August 9, 2025 22:51
…tensions

- removed the As(UnitSystem) method from the IQuantity interface
Split tests into ToUnit vs ToUnitTyped
Update calls to ToUnitTyped where output is IQuantity.
…interface with an extension method ([Obsolete])

- renamed the ToUnitUntyped extension back to ToUnit and made it [Obsolete]
- replaced the generated UnitSystem tests for the IQuantity / IQuantity<TUnit> with a single set of tests in the IQauntityTests
@lipchev
Copy link
Collaborator Author

lipchev commented Aug 16, 2025

@angularsen This corresponds to option 2) from this comment: #1600 (comment)

Comment on lines 413 to -432
public void ToUnit_UnitSystem_ReturnsValueInDimensionlessUnit()
{{
Assert.Multiple(() =>
{{
var quantity = new {_quantity.Name}(value: 1, unit: {_baseUnitFullName});
{_quantity.Name} convertedQuantity = quantity.ToUnit(UnitSystem.SI);
Assert.Equal({_baseUnitFullName}, convertedQuantity.Unit);
Assert.Equal(quantity.Value, convertedQuantity.Value);
}}, () =>
{{
IQuantity<{_unitEnumName}> quantity = new {_quantity.Name}(value: 1, unit: {_baseUnitFullName});
IQuantity<{_unitEnumName}> convertedQuantity = quantity.ToUnit(UnitSystem.SI);
Assert.Equal({_baseUnitFullName}, convertedQuantity.Unit);
Assert.Equal(quantity.Value, convertedQuantity.Value);
}});
}}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I've only kept the concrete part of this test, but on second thought there shouldn't really be any need for it to exist here either- as we already have tests for the UnitSystem constructor.
In case we decide to move forward with the removal of the interface methods from the interface in v6, then these tests should probably go to another test file- something like QuantityExtensionsTests.

@lipchev
Copy link
Collaborator Author

lipchev commented Aug 19, 2025

@angularsen This corresponds to option 2) from this comment: #1600 (comment)

One point I forgot to mention in the other thread was the requirement for using UnitsNet. This isn't a big deal most of the time, and importing the namespaces from the IDE isn't very difficult, however if we wanted to minimize these cases, we could potentially have the unit conversion extensions, of which we currently only support the ones with UnitSystem (but you know the As(TUnit) and ToUnit(TUnit) are coming in the 🐲 ), moved to the UnitsNet.Units namespace, where the actual units are defined. This is why in the 🐲 PR I used to have these extensions placed in the UnitConversionExtensions class (until last night, when I forgot about the whole namespace-trick-thing and merged them back into the QuantityExtensions).

So, there you have it, another thing for you to consider (I can't say I have any preferences- one way or the other).

@angularsen
Copy link
Owner

@claude Review the PR

@claude
Copy link

claude bot commented Sep 21, 2025

Claude encountered an error —— View job

Failed with exit code 128

I'll analyze this and get back to you.

@angularsen
Copy link
Owner

Claude code does not yet work with PRs from forks, here is a local review:

Code Review for PR #1606: Replace ToUnit(UnitSystem) from IQuantity interface with extension method

📋 Summary

This PR refactors the ToUnit(UnitSystem) method by moving it from the IQuantity interface to extension methods,
marking them as obsolete for future removal. The changes affect 265 files with a net reduction of ~8,000 lines of code.

⚠️ Breaking Changes

  • Removed from interface: ToUnit(UnitSystem) is no longer part of IQuantity interface
  • Impact: Custom quantity implementations relying on the interface method will break
  • Migration path: Add using UnitsNet; to access the extension methods
  • Backward compatibility: Maintained through [Obsolete] extension methods

✅ Style and Conventions

  • Proper use of [Obsolete] attributes with clear messaging
  • Extension methods appropriately placed in QuantityExtensions.cs
  • XML documentation is comprehensive and follows project standards
  • Follows existing code patterns and .editorconfig specifications

🏗️ Code Quality and Architecture

Improvements:

  • Massive code reduction: ~8,000 lines removed from generated code
  • Better separation of concerns: Interface focuses on core functionality
  • Consolidated testing: 131 duplicate test implementations → single location in IQuantityTests.cs
  • Simplified code generation: Cleaner templates in QuantityGenerator.cs

Implementation details:

// Before (in interface)
IQuantity<TUnitType> ToUnit(UnitSystem unitSystem);

// After (as extension)
[Obsolete("This method will be removed from the interface in the next major update.")]
public static IQuantity<TUnit> ToUnit<TUnit>(this IQuantity<TUnit> quantity, UnitSystem unitSystem)

🧪 Test Coverage

  • ✅ All scenarios still covered
  • ✅ Tests properly consolidated from 131 files to IQuantityTests.cs
  • ✅ Both IQuantity and IQuantity extension methods tested
  • ✅ Edge cases (null, unsupported systems) verified

🔍 Potential Issues

Issue Impact Recommendation
Namespace requirement Users need using UnitsNet; Document prominently in release notes
Custom implementations External implementations will break Provide migration guide
Deprecation timeline Not specified in obsolete message Add timeline (e.g., "Will be removed in v6.0")

🚀 Performance

No performance impact - implementation logic unchanged, just relocated.

💡 Suggestions

  1. Documentation:
  • Add deprecation timeline to obsolete message
  • Create migration guide for custom implementations
  • Update README with breaking changes
  1. Consider namespace optimization:
  • The suggestion to move extensions to UnitsNet.Units namespace could reduce friction
  • Would eliminate need for additional using statement in many cases
  1. Example migration for users:
// Old (won't compile after removal)
IQuantity<LengthUnit> length = Length.FromMeters(1);
var converted = length.ToUnit(UnitSystem.SI);

```cs
// New (requires using UnitsNet;)
using UnitsNet; // Add this
IQuantity<LengthUnit> length = Length.FromMeters(1);
var converted = length.ToUnit(UnitSystem.SI); // Now works as extension

✅ Verdict

Approved with minor suggestions. This is a well-executed refactoring that significantly improves code maintainability. The
breaking changes are justified by the substantial code reduction and architectural improvements. The deprecation path is
reasonable and maintains backward compatibility during the transition period.

@angularsen angularsen merged commit bde4d1a into angularsen:master Sep 21, 2025
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants