Skip to content

Add statically-typed UnitInfo classes #1024

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

Closed
wants to merge 9 commits into from
Closed
167 changes: 118 additions & 49 deletions CodeGen/Generators/UnitsNetGen/QuantityGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ public partial struct {_quantity.Name} : IQuantity<{_unitEnumName}>, ");
GenerateConversionMethods();
GenerateToString();
GenerateIConvertibleMethods();
GenerateQuantityInfoClass();

Writer.WL($@"
}}
Expand All @@ -116,53 +117,25 @@ public partial struct {_quantity.Name} : IQuantity<{_unitEnumName}>, ");
private void GenerateStaticConstructor()
{
var baseDimensions = _quantity.BaseDimensions;

Writer.WL($@"
static {_quantity.Name}()
{{");
Writer.WL(_isDimensionless
? @"
BaseDimensions = BaseDimensions.Dimensionless;
"
Writer.WL(_isDimensionless ? @"
BaseDimensions = BaseDimensions.Dimensionless;"
: $@"
BaseDimensions = new BaseDimensions({baseDimensions.L}, {baseDimensions.M}, {baseDimensions.T}, {baseDimensions.I}, {baseDimensions.Θ}, {baseDimensions.N}, {baseDimensions.J});
");
BaseDimensions = new BaseDimensions({baseDimensions.L}, {baseDimensions.M}, {baseDimensions.T}, {baseDimensions.I}, {baseDimensions.Θ}, {baseDimensions.N}, {baseDimensions.J});");

Writer.WL($@"
Info = new QuantityInfo<{_unitEnumName}>(""{_quantity.Name}"",
new UnitInfo<{_unitEnumName}>[] {{");

foreach (var unit in _quantity.Units)
{
var baseUnits = unit.BaseUnits;
if (baseUnits == null)
{
Writer.WL($@"
new UnitInfo<{_unitEnumName}>({_unitEnumName}.{unit.SingularName}, ""{unit.PluralName}"", BaseUnits.Undefined),");
}
else
{
var baseUnitsCtorArgs = string.Join(", ",
new[]
{
baseUnits.L != null ? $"length: LengthUnit.{baseUnits.L}" : null,
baseUnits.M != null ? $"mass: MassUnit.{baseUnits.M}" : null,
baseUnits.T != null ? $"time: DurationUnit.{baseUnits.T}" : null,
baseUnits.I != null ? $"current: ElectricCurrentUnit.{baseUnits.I}" : null,
baseUnits.Θ != null ? $"temperature: TemperatureUnit.{baseUnits.Θ}" : null,
baseUnits.N != null ? $"amount: AmountOfSubstanceUnit.{baseUnits.N}" : null,
baseUnits.J != null ? $"luminousIntensity: LuminousIntensityUnit.{baseUnits.J}" : null
}.Where(str => str != null));

Writer.WL($@"
new UnitInfo<{_unitEnumName}>({_unitEnumName}.{unit.SingularName}, ""{unit.PluralName}"", new BaseUnits({baseUnitsCtorArgs})),");
}
}

Writer.WL($@"
}},
BaseUnit, Zero, BaseDimensions, QuantityType.{_quantity.Name});
BaseUnit = {_unitEnumName}.{_quantity.BaseUnit};
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 initialized all static properties in the constructor now to guarantee order

MaxValue = new {_quantity.Name}({_valueType}.MaxValue, BaseUnit);
MinValue = new {_quantity.Name}({_valueType}.MinValue, BaseUnit);
QuantityType = QuantityType.{_quantity.Name};
Units = Enum.GetValues(typeof({_unitEnumName})).Cast<{_unitEnumName}>().Except(new {_unitEnumName}[]{{ {_unitEnumName}.Undefined }}).ToArray();
Zero = new {_quantity.Name}(0, BaseUnit);
Info = new {_quantity.Name}QuantityInfo();
}}
");
" );
}

private void GenerateInstanceConstructors()
Expand Down Expand Up @@ -218,11 +191,11 @@ private void GenerateInstanceConstructors()

private void GenerateStaticProperties()
{
Writer.WL($@"
Writer.W($@"
#region Static Properties

/// <inheritdoc cref=""IQuantity.QuantityInfo""/>
public static QuantityInfo<{_unitEnumName}> Info {{ get; }}
public static {_quantity.Name}QuantityInfo Info {{ get; }}

/// <summary>
/// The <see cref=""BaseDimensions"" /> of this quantity.
Expand All @@ -232,37 +205,38 @@ private void GenerateStaticProperties()
/// <summary>
/// The base unit of {_quantity.Name}, which is {_quantity.BaseUnit}. All conversions go via this value.
/// </summary>
public static {_unitEnumName} BaseUnit {{ get; }} = {_unitEnumName}.{_quantity.BaseUnit};
public static {_unitEnumName} BaseUnit {{ get; }}

/// <summary>
/// Represents the largest possible value of {_quantity.Name}
/// </summary>
[Obsolete(""MaxValue and MinValue will be removed. Choose your own value or use nullability for unbounded lower/upper range checks. See discussion in https://github.com/angularsen/UnitsNet/issues/848."")]
public static {_quantity.Name} MaxValue {{ get; }} = new {_quantity.Name}({_valueType}.MaxValue, BaseUnit);
public static {_quantity.Name} MaxValue {{ get; }}

/// <summary>
/// Represents the smallest possible value of {_quantity.Name}
/// </summary>
[Obsolete(""MaxValue and MinValue will be removed. Choose your own value or use nullability for unbounded lower/upper range checks. See discussion in https://github.com/angularsen/UnitsNet/issues/848."")]
public static {_quantity.Name} MinValue {{ get; }} = new {_quantity.Name}({_valueType}.MinValue, BaseUnit);
public static {_quantity.Name} MinValue {{ get; }}

/// <summary>
/// The <see cref=""QuantityType"" /> of this quantity.
/// </summary>
[Obsolete(""QuantityType will be removed in the future. Use the Info property instead."")]
public static QuantityType QuantityType {{ get; }} = QuantityType.{_quantity.Name};
public static QuantityType QuantityType {{ get; }}

/// <summary>
/// All units of measurement for the {_quantity.Name} quantity.
/// </summary>
public static {_unitEnumName}[] Units {{ get; }} = Enum.GetValues(typeof({_unitEnumName})).Cast<{_unitEnumName}>().Except(new {_unitEnumName}[]{{ {_unitEnumName}.Undefined }}).ToArray();
public static {_unitEnumName}[] Units {{ get; }}

/// <summary>
/// Gets an instance of this quantity with a value of 0 in the base unit {_quantity.BaseUnit}.
/// </summary>
public static {_quantity.Name} Zero {{ get; }} = new {_quantity.Name}(0, BaseUnit);
public static {_quantity.Name} Zero {{ get; }}

#endregion

");
}

Expand Down Expand Up @@ -1185,7 +1159,102 @@ ulong IConvertible.ToUInt64(IFormatProvider provider)
return Convert.ToUInt64(_value);
}}

#endregion");
#endregion
");
}

private void GenerateQuantityInfoClass()
{
Writer.WL($@"
/// <summary>
/// The <see cref=""QuantityInfo{{{_unitEnumName}}}""/> for the <see cref=""{_quantity.Name}""/> quantity and its units.
/// </summary>
public sealed class {_quantity.Name}QuantityInfo : QuantityInfo<{_unitEnumName}>
{{
/// <summary>
/// Constructs an instance of the <see cref=""{_quantity.Name}QuantityInfo""/> class.
/// </summary>
internal {_quantity.Name}QuantityInfo() :
base(""{_quantity.Name}"",
new UnitInfo<{_unitEnumName}>[]
{{");

foreach( var unit in _quantity.Units )
{
var baseUnits = unit.BaseUnits;
if( baseUnits == null )
{
Writer.WL( $@"
new UnitInfo<{_unitEnumName}>({_unitEnumName}.{unit.SingularName}, ""{unit.PluralName}"", BaseUnits.Undefined)," );
}
else
{
var baseUnitsCtorArgs = string.Join( ", ",
new[]
{
baseUnits.L != null ? $"length: LengthUnit.{baseUnits.L}" : null,
baseUnits.M != null ? $"mass: MassUnit.{baseUnits.M}" : null,
baseUnits.T != null ? $"time: DurationUnit.{baseUnits.T}" : null,
baseUnits.I != null ? $"current: ElectricCurrentUnit.{baseUnits.I}" : null,
baseUnits.Θ != null ? $"temperature: TemperatureUnit.{baseUnits.Θ}" : null,
baseUnits.N != null ? $"amount: AmountOfSubstanceUnit.{baseUnits.N}" : null,
baseUnits.J != null ? $"luminousIntensity: LuminousIntensityUnit.{baseUnits.J}" : null
}.Where( str => str != null ) );

Writer.WL( $@"
new UnitInfo<{_unitEnumName}>({_unitEnumName}.{unit.SingularName}, ""{unit.PluralName}"", new BaseUnits({baseUnitsCtorArgs}))," );
}
}

Writer.WL( $@"
}},
{_quantity.Name}.BaseUnit, {_quantity.Name}.Zero, {_quantity.Name}.BaseDimensions, QuantityType.{_quantity.Name})
{{");

foreach( var unit in _quantity.Units )
{
var baseUnits = unit.BaseUnits;
if( baseUnits == null )
{
Writer.WL( $@"
{unit.SingularName} = new UnitInfo<{_unitEnumName}>({_unitEnumName}.{unit.SingularName}, ""{unit.PluralName}"", BaseUnits.Undefined);" );
}
else
{
var baseUnitsCtorArgs = string.Join( ", ",
new[]
{
baseUnits.L != null ? $"length: LengthUnit.{baseUnits.L}" : null,
baseUnits.M != null ? $"mass: MassUnit.{baseUnits.M}" : null,
baseUnits.T != null ? $"time: DurationUnit.{baseUnits.T}" : null,
baseUnits.I != null ? $"current: ElectricCurrentUnit.{baseUnits.I}" : null,
baseUnits.Θ != null ? $"temperature: TemperatureUnit.{baseUnits.Θ}" : null,
baseUnits.N != null ? $"amount: AmountOfSubstanceUnit.{baseUnits.N}" : null,
baseUnits.J != null ? $"luminousIntensity: LuminousIntensityUnit.{baseUnits.J}" : null
}.Where( str => str != null ) );

Writer.WL( $@"

{unit.SingularName} = new UnitInfo<{_unitEnumName}>({_unitEnumName}.{unit.SingularName}, ""{unit.PluralName}"", new BaseUnits({baseUnitsCtorArgs}));" );
}
}

Writer.WL($@"
}}
");

foreach( var unit in _quantity.Units )
{
Writer.WL( $@"
/// <summary>
/// Gets the <see cref=""UnitInfo{{{_unitEnumName}}}""/> for <see cref=""{_unitEnumName}.{unit.SingularName}""/>
/// </summary>
public UnitInfo<{_unitEnumName}> {unit.SingularName} {{ get; }}
" );
}

Writer.WL( $@"
}}" );
}

/// <inheritdoc cref="GetObsoleteAttributeOrNull(string)"/>
Expand Down
Loading