@@ -252,15 +252,19 @@ public sealed class {quantityInfoClassName}: QuantityInfo<{_quantity.Name}, {_un
252252 } . Where ( str => str != null ) ) } )" ;
253253 }
254254
255+ // the UnitInfo constructor has 3 overloads:
256+ // - one for the base unit without conversion expressions
257+ // - one for units with only FromBaseToUnit conversion expression (with the FromUnitToBase expression assumed to be the inverse)
258+ // - one for units with both FromBaseToUnit and FromUnitToBase conversion expressions (required when the conversion is not a simple inverse, e.g. affine conversions)
255259 if ( unit . SingularName == _quantity . BaseUnit )
256260 {
257261 Writer . WL ( $@ "
258262 yield return new ({ _unitEnumName } .{ unit . SingularName } , ""{ unit . SingularName } "", ""{ unit . PluralName } "", { baseUnitsFormat } );" ) ;
259263 }
260264 else
261265 {
262- // note: omitting the extra parameter (where possible) saves us 36 KB
263266 CompositeExpression expressionFromBaseToUnit = ExpressionEvaluator . Evaluate ( unit . FromBaseToUnitFunc , "{x}" ) ;
267+ // Check if FromUnitToBase is simply the inverse of FromBaseToUnit
264268 if ( expressionFromBaseToUnit . Terms . Count == 1 && expressionFromBaseToUnit . Degree == Fraction . One )
265269 {
266270 Writer . WL ( $@ "
@@ -732,9 +736,7 @@ private void GenerateArithmeticOperators()
732736
733737 private void GenerateLogarithmicArithmeticOperators ( )
734738 {
735- var scalingFactor = _quantity . LogarithmicScalingFactor ;
736739 // Most logarithmic operators need a simple scaling factor of 10. However, certain units such as voltage ratio need to use 20 instead.
737- var x = ( 10 * scalingFactor ) . ToString ( ) ;
738740 Writer . WL ( $@ "
739741 #region Logarithmic Arithmetic Operators
740742
@@ -750,10 +752,7 @@ private void GenerateLogarithmicArithmeticOperators()
750752 /// </remarks>
751753 public static { _quantity . Name } operator +({ _quantity . Name } left, { _quantity . Name } right)
752754 {{
753- // Logarithmic addition
754- // Formula: { x } * log10(10^(x/{ x } ) + 10^(y/{ x } ))
755- var leftUnit = left.Unit;
756- return new { _quantity . Name } (QuantityValueExtensions.AddWithLogScaling(left.Value, right.As(leftUnit), LogarithmicScalingFactor), leftUnit);
755+ return new { _quantity . Name } (QuantityValueExtensions.AddWithLogScaling(left.Value, right.As(left.Unit), LogarithmicScalingFactor), left.Unit);
757756 }}
758757
759758 /// <summary>Get <see cref=""{ _quantity . Name } ""/> from logarithmic subtraction of two <see cref=""{ _quantity . Name } ""/>.</summary>
@@ -762,37 +761,30 @@ private void GenerateLogarithmicArithmeticOperators()
762761 /// </remarks>
763762 public static { _quantity . Name } operator -({ _quantity . Name } left, { _quantity . Name } right)
764763 {{
765- // Logarithmic subtraction
766- // Formula: { x } * log10(10^(x/{ x } ) - 10^(y/{ x } ))
767- var leftUnit = left.Unit;
768- return new { _quantity . Name } (QuantityValueExtensions.SubtractWithLogScaling(left.Value, right.As(leftUnit), LogarithmicScalingFactor), leftUnit);
764+ return new { _quantity . Name } (QuantityValueExtensions.SubtractWithLogScaling(left.Value, right.As(left.Unit), LogarithmicScalingFactor), left.Unit);
769765 }}
770766
771767 /// <summary>Get <see cref=""{ _quantity . Name } ""/> from logarithmic multiplication of value and <see cref=""{ _quantity . Name } ""/>.</summary>
772768 public static { _quantity . Name } operator *(QuantityValue left, { _quantity . Name } right)
773769 {{
774- // Logarithmic multiplication = addition
775770 return new { _quantity . Name } (left + right.Value, right.Unit);
776771 }}
777772
778773 /// <summary>Get <see cref=""{ _quantity . Name } ""/> from logarithmic multiplication of value and <see cref=""{ _quantity . Name } ""/>.</summary>
779774 public static { _quantity . Name } operator *({ _quantity . Name } left, QuantityValue right)
780775 {{
781- // Logarithmic multiplication = addition
782776 return new { _quantity . Name } (left.Value + right, left.Unit);
783777 }}
784778
785779 /// <summary>Get <see cref=""{ _quantity . Name } ""/> from logarithmic division of <see cref=""{ _quantity . Name } ""/> by value.</summary>
786780 public static { _quantity . Name } operator /({ _quantity . Name } left, QuantityValue right)
787781 {{
788- // Logarithmic division = subtraction
789782 return new { _quantity . Name } (left.Value - right, left.Unit);
790783 }}
791784
792785 /// <summary>Get ratio value from logarithmic division of <see cref=""{ _quantity . Name } ""/> by <see cref=""{ _quantity . Name } ""/>.</summary>
793786 public static QuantityValue operator /({ _quantity . Name } left, { _quantity . Name } right)
794787 {{
795- // Logarithmic division = subtraction
796788 return left.Value - right.As(left.Unit);
797789 }}
798790
@@ -801,11 +793,16 @@ private void GenerateLogarithmicArithmeticOperators()
801793 }
802794
803795 /// <summary>
804- /// Generates operators that express relations between quantities as applied by <see cref="QuantityRelationsParser" /> .
796+ /// Generates relational operators for quantities based on their defined relations .
805797 /// </summary>
806- private void GenerateRelationalOperators ( )
798+ /// <param name="inverseWithFixedUnit">
799+ /// Specifies whether inverse relational operators should be generated as implicit conversions or simply using the unit specified in the UnitRelations.
800+ /// If <c>true</c>, the method generates inverse operators that convert to a fixed unit, as specified in the UnitRelations.
801+ /// If <c>false</c>, the method generates inverse operators as implicit conversions that utilize the UnitConverter for conversion.
802+ /// </param>
803+ private void GenerateRelationalOperators ( bool inverseWithFixedUnit = false )
807804 {
808- if ( ! _quantity . Relations . Any ( ) ) return ;
805+ if ( _quantity . Relations . Length == 0 ) return ;
809806
810807 Writer . WL ( $@ "
811808 #region Relational Operators
@@ -815,96 +812,30 @@ private void GenerateRelationalOperators()
815812 {
816813 if ( relation . Operator == "inverse" )
817814 {
818- Writer . WL ( $@ "
815+ if ( inverseWithFixedUnit )
816+ {
817+ // this was the original behavior where the inverse always used the fixed unit from the relation
818+ Writer . WL ( $@ "
819819 /// <summary>Calculates the inverse of this quantity.</summary>
820820 /// <returns>The corresponding inverse quantity, <see cref=""{ relation . RightQuantity . Name } ""/>.</returns>
821821 public { relation . RightQuantity . Name } Inverse()
822822 {{
823- return UnitConverter.Default.ConvertTo(Value, Unit, { relation . RightQuantity . Name } .Info );
823+ return { relation . RightQuantity . Name } .From { relation . RightUnit . PluralName } (QuantityValue.Inverse( { relation . LeftUnit . PluralName } ) );
824824 }}
825825" ) ;
826- }
827- else
828- {
829- var leftParameterType = relation . LeftQuantity . Name ;
830- var leftParameterName = leftParameterType . ToCamelCase ( ) ;
831- var leftConversionProperty = relation . LeftUnit . PluralName ;
832- var rightParameterType = relation . RightQuantity . Name ;
833- var rightParameterName = relation . RightQuantity . Name . ToCamelCase ( ) ;
834- var rightConversionProperty = relation . RightUnit . PluralName ;
835-
836- if ( leftParameterName == rightParameterName )
837- {
838- leftParameterName = "left" ;
839- rightParameterName = "right" ;
840- }
841-
842- var leftPart = $ "{ leftParameterName } .{ leftConversionProperty } ";
843- var rightPart = $ "{ rightParameterName } .{ rightConversionProperty } ";
844-
845- if ( leftParameterName is "double" )
846- {
847- leftParameterType = "QuantityValue" ;
848- leftParameterName = leftPart = "value" ;
849- }
850-
851- if ( rightParameterName is "double" )
852- {
853- rightParameterType = "QuantityValue" ;
854- rightParameterName = rightPart = "value" ;
855- }
856-
857- var expression = $ "{ leftPart } { relation . Operator } { rightPart } ";
858-
859- var resultType = relation . ResultQuantity . Name ;
860- if ( resultType is "double" )
861- {
862- resultType = "QuantityValue" ;
863826 }
864827 else
865828 {
866- expression = $ "{ resultType } .From{ relation . ResultUnit . PluralName } ({ expression } )";
867- }
868-
869- Writer . WL ( $@ "
870- /// <summary>Get <see cref=""{ resultType } ""/> from <see cref=""{ leftParameterType } ""/> { relation . Operator } <see cref=""{ rightParameterType } ""/>.</summary>
871- public static { resultType } operator { relation . Operator } ({ leftParameterType } { leftParameterName } , { rightParameterType } { rightParameterName } )
872- {{
873- return { expression } ;
874- }}
875- " ) ;
876- }
877- }
878-
879- Writer . WL ( $@ "
880-
881- #endregion
882- " ) ;
883- }
884-
885- /// <summary>
886- /// Generates operators that express relations between quantities as applied by <see cref="QuantityRelationsParser" />.
887- /// </summary>
888- private void GenerateRelationalOperatorsWithFixedUnits ( )
889- {
890- if ( ! _quantity . Relations . Any ( ) ) return ;
891-
892- Writer . WL ( $@ "
893- #region Relational Operators
894- " ) ;
895-
896- foreach ( QuantityRelation relation in _quantity . Relations )
897- {
898- if ( relation . Operator == "inverse" )
899- {
900- Writer . WL ( $@ "
829+ // this is the proposed improvement where the inverse is considered a type of implicit conversion
830+ Writer . WL ( $@ "
901831 /// <summary>Calculates the inverse of this quantity.</summary>
902832 /// <returns>The corresponding inverse quantity, <see cref=""{ relation . RightQuantity . Name } ""/>.</returns>
903833 public { relation . RightQuantity . Name } Inverse()
904834 {{
905- return { relation . RightQuantity . Name } .From { relation . RightUnit . PluralName } (QuantityValue.Inverse( { relation . LeftUnit . PluralName } ) );
835+ return UnitConverter.Default.ConvertTo(Value, Unit, { relation . RightQuantity . Name } .Info );
906836 }}
907837" ) ;
838+ }
908839 }
909840 else
910841 {
@@ -993,20 +924,43 @@ private void GenerateEqualityAndComparison()
993924 return left.Value > right.As(left.Unit);
994925 }}
995926
996- /// <summary>Indicates strict equality of two <see cref=""{ _quantity . Name } ""/> quantities.</summary>
927+ /// <summary>
928+ /// Determines whether two <see cref=""{ _quantity . Name } ""/> instances are equal.
929+ /// </summary>
930+ /// <remarks>
931+ /// Equality is evaluated in a unit-aware manner. The right-hand operand is converted to the unit of the left-hand
932+ /// operand and then the underlying numeric values are compared.
933+ /// This means two quantities with numerically equal values but different units will be considered equal.
934+ /// The operator delegates to <see cref=""Equals({ _quantity . Name } )""/>, which implements this conversion-and-compare logic.
935+ /// </remarks>
997936 public static bool operator ==({ _quantity . Name } left, { _quantity . Name } right)
998937 {{
999938 return left.Equals(right);
1000939 }}
1001940
1002- /// <summary>Indicates strict inequality of two <see cref=""{ _quantity . Name } ""/> quantities.</summary>
941+ /// <summary>
942+ /// Determines whether two <see cref=""{ _quantity . Name } ""/> instances are not equal.
943+ /// </summary>
944+ /// <remarks>
945+ /// This operator is the logical negation of <see cref=""operator ==({ _quantity . Name } ,{ _quantity . Name } )""/>.
946+ /// See that operator (and <see cref=""Equals({ _quantity . Name } )""/>) for details on how equality is evaluated
947+ /// (i.e., by converting one operand to the other's unit and comparing their numeric values).
948+ /// </remarks>
1003949 public static bool operator !=({ _quantity . Name } left, { _quantity . Name } right)
1004950 {{
1005951 return !(left == right);
1006952 }}
1007953
1008954 /// <inheritdoc />
1009- /// <summary>Indicates strict equality of two <see cref=""{ _quantity . Name } ""/> quantities.</summary>
955+ /// <summary>
956+ /// Determines whether the specified object is equal to the current <see cref=""{ _quantity . Name } ""/> instance.
957+ /// </summary>
958+ /// <remarks>
959+ /// Returns <c>false</c> if <paramref name=""obj""/> is <c>null</c> or not a <see cref=""{ _quantity . Name } ""/>.
960+ /// When <paramref name=""obj""/> is a <see cref=""{ _quantity . Name } ""/>, this method delegates to
961+ /// <see cref=""Equals({ _quantity . Name } )""/>, which performs a unit-aware comparison by converting the other
962+ /// instance to this instance's unit before comparing numeric values.
963+ /// </remarks>
1010964 public override bool Equals(object? obj)
1011965 {{
1012966 if (obj is not { _quantity . Name } otherQuantity)
@@ -1016,7 +970,13 @@ public override bool Equals(object? obj)
1016970 }}
1017971
1018972 /// <inheritdoc />
1019- /// <summary>Indicates strict equality of two <see cref=""{ _quantity . Name } ""/> quantities.</summary>
973+ /// <summary>
974+ /// Determines whether the current instance is equal to another <see cref=""{ _quantity . Name } ""/> instance.
975+ /// </summary>
976+ /// <remarks>
977+ /// Comparison is performed by converting <paramref name=""other""/> to this instance's unit and then comparing the underlying numeric values.
978+ /// This makes two quantities equal even when their units differ, provided the converted numeric values are equal.
979+ /// </remarks>
1020980 public bool Equals({ _quantity . Name } other)
1021981 {{
1022982 return _value.Equals(other.As(this.Unit));
0 commit comments