-
Notifications
You must be signed in to change notification settings - Fork 393
Move default unit converter registration to quantity types #1018
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
Move default unit converter registration to quantity types #1018
Conversation
I am hoping this fixes #1016, but even if not, I think it's a bit easier to find what's going on in the static constructors. Hopefully this would also bring down our "startup" time a bit. |
Codecov Report
@@ Coverage Diff @@
## master #1018 +/- ##
========================================
+ Coverage 82.8% 82.9% +0.1%
========================================
Files 310 309 -1
Lines 46695 46928 +233
========================================
+ Hits 38635 38867 +232
- Misses 8060 8061 +1
Continue to review full report at Codecov.
|
@angularsen any idea what the issue is with codecov project? |
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.
Just skimmed it, one question
@@ -72,6 +72,39 @@ static Acceleration() | |||
new UnitInfo<AccelerationUnit>(AccelerationUnit.StandardGravity, "StandardGravity", new BaseUnits(length: LengthUnit.Meter, time: DurationUnit.Second)), | |||
}, | |||
BaseUnit, Zero, BaseDimensions, QuantityType.Acceleration); | |||
|
|||
// Register in default unit converter: BaseUnit -> AccelerationUnit | |||
UnitConverter.Default.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.CentimeterPerSecondSquared, quantity => quantity.ToUnit(AccelerationUnit.CentimeterPerSecondSquared)); |
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.
Ok, interesting idea to break things up while not requiring the client to call some init method of sorts. It could help with both the issue and startup time.
I am wondering, can this result in conversions failing in some way? That they are not initialized yet, because the Acceleration static ctor just wasn't called yet in that particular call path?
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.
Aha, yes. If you call the following:
var func = UnitConverter.Default.GetConversionFunction<Acceleration>( AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.KilometerPerSecondSquared );
It fails since it has not been registered yet, despite having the Acceleration type utilized. Let me see if I can fix this.
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.
Ok, I created a separate internal static RegisterDefaultConversions method in each of our quantities. I use reflection on the first call to the UnitConverter (as before) to register them all. This makes sure everything is initialized as-before, but without a giant method with all the types hard-coded into it.
Startup time won't be improved now, but hopefully the original problem will be resolved. It is nicer to look at also :)
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.
Nice 🐷💄
It seems the PR diff is fine, but not the merged PR. It seems to stumble on -0.0%. Migth be a configuration error. I know I had to upgrade the codecov uploader script recently, so it might be related. I think we can just ignore it for now. |
Ok sounds good. |
…ection from UnitConverter
@tmilnthorp A merge conflict after some recent PRs merged |
@angularsen fixed |
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 think this looks great, just the merge conflict and some minor suggestions you can consider.
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MillistandardGravity, AccelerationUnit.MeterPerSecondSquared, quantity => quantity.ToBaseUnit()); | ||
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.NanometerPerSecondSquared, AccelerationUnit.MeterPerSecondSquared, quantity => quantity.ToBaseUnit()); | ||
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.StandardGravity, AccelerationUnit.MeterPerSecondSquared, quantity => quantity.ToBaseUnit()); | ||
} |
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 like the new structure ♥
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.
A minor idea, but since we are just about always adding two-way conversions, could SetConversionFunction
have an overload method to define both ways in one call?
Pretty much just an extra conversion function parameter if I am reading it right.
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.
Could be named SetTwoWayConversionFunctions
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.
A minor idea, but since we are just about always adding two-way conversions, could
SetConversionFunction
have an overload method to define both ways in one call?Pretty much just an extra conversion function parameter if I am reading it right.
I tried adding an overload, but IMHO the lines became a bit more "mentally taxing" (even more so than it already is). It is certainly shorter in height though:
public void SetConversionFunction<TQuantity>(Enum from, Enum to, ConversionFunction<TQuantity> conversionFunction, ConversionFunction<TQuantity> reverseConversionFunction)
where TQuantity : IQuantity
{
}
/// <summary>
/// Registers the default conversion functions in the given <see cref="UnitConverter"/> instance.
/// </summary>
/// <param name="unitConverter">The <see cref="UnitConverter"/> to register the default conversion functions in.</param>
internal static void RegisterDefaultConversions(UnitConverter unitConverter)
{
// Register in unit converter: BaseUnit <-> BaseUnit
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.MeterPerSecondSquared, quantity => quantity);
// Register in unit converter: BaseUnit -> AccelerationUnit
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.CentimeterPerSecondSquared, quantity => quantity.ToUnit(AccelerationUnit.CentimeterPerSecondSquared), quantity => quantity.ToBaseUnit());
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.DecimeterPerSecondSquared, quantity => quantity.ToUnit(AccelerationUnit.DecimeterPerSecondSquared), quantity => quantity.ToBaseUnit());
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.FootPerSecondSquared, quantity => quantity.ToUnit(AccelerationUnit.FootPerSecondSquared), quantity => quantity.ToBaseUnit());
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.InchPerSecondSquared, quantity => quantity.ToUnit(AccelerationUnit.InchPerSecondSquared), quantity => quantity.ToBaseUnit());
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.KilometerPerSecondSquared, quantity => quantity.ToUnit(AccelerationUnit.KilometerPerSecondSquared), quantity => quantity.ToBaseUnit());
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.KnotPerHour, quantity => quantity.ToUnit(AccelerationUnit.KnotPerHour), quantity => quantity.ToBaseUnit());
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.KnotPerMinute, quantity => quantity.ToUnit(AccelerationUnit.KnotPerMinute), quantity => quantity.ToBaseUnit());
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.KnotPerSecond, quantity => quantity.ToUnit(AccelerationUnit.KnotPerSecond), quantity => quantity.ToBaseUnit());
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.MicrometerPerSecondSquared, quantity => quantity.ToUnit(AccelerationUnit.MicrometerPerSecondSquared), quantity => quantity.ToBaseUnit());
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.MillimeterPerSecondSquared, quantity => quantity.ToUnit(AccelerationUnit.MillimeterPerSecondSquared), quantity => quantity.ToBaseUnit());
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.MillistandardGravity, quantity => quantity.ToUnit(AccelerationUnit.MillistandardGravity), quantity => quantity.ToBaseUnit());
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.NanometerPerSecondSquared, quantity => quantity.ToUnit(AccelerationUnit.NanometerPerSecondSquared), quantity => quantity.ToBaseUnit());
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.StandardGravity, quantity => quantity.ToUnit(AccelerationUnit.StandardGravity), quantity => quantity.ToBaseUnit());
}
Breaking it into multiple lines gets even worse:
/// <summary>
/// Registers the default conversion functions in the given <see cref="UnitConverter"/> instance.
/// </summary>
/// <param name="unitConverter">The <see cref="UnitConverter"/> to register the default conversion functions in.</param>
internal static void RegisterDefaultConversions(UnitConverter unitConverter)
{
// Register in unit converter: BaseUnit <-> BaseUnit
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.MeterPerSecondSquared, quantity => quantity);
// Register in unit converter: BaseUnit -> AccelerationUnit
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.CentimeterPerSecondSquared,
quantity => quantity.ToUnit(AccelerationUnit.CentimeterPerSecondSquared), quantity => quantity.ToBaseUnit());
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.DecimeterPerSecondSquared,
quantity => quantity.ToUnit(AccelerationUnit.DecimeterPerSecondSquared), quantity => quantity.ToBaseUnit());
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.FootPerSecondSquared,
quantity => quantity.ToUnit(AccelerationUnit.FootPerSecondSquared), quantity => quantity.ToBaseUnit());
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.InchPerSecondSquared,
quantity => quantity.ToUnit(AccelerationUnit.InchPerSecondSquared), quantity => quantity.ToBaseUnit());
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.KilometerPerSecondSquared,
quantity => quantity.ToUnit(AccelerationUnit.KilometerPerSecondSquared), quantity => quantity.ToBaseUnit());
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.KnotPerHour,
quantity => quantity.ToUnit(AccelerationUnit.KnotPerHour), quantity => quantity.ToBaseUnit());
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.KnotPerMinute,
quantity => quantity.ToUnit(AccelerationUnit.KnotPerMinute), quantity => quantity.ToBaseUnit());
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.KnotPerSecond,
quantity => quantity.ToUnit(AccelerationUnit.KnotPerSecond), quantity => quantity.ToBaseUnit());
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.MicrometerPerSecondSquared,
quantity => quantity.ToUnit(AccelerationUnit.MicrometerPerSecondSquared), quantity => quantity.ToBaseUnit());
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.MillimeterPerSecondSquared,
quantity => quantity.ToUnit(AccelerationUnit.MillimeterPerSecondSquared), quantity => quantity.ToBaseUnit());
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.MillistandardGravity,
quantity => quantity.ToUnit(AccelerationUnit.MillistandardGravity), quantity => quantity.ToBaseUnit());
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.NanometerPerSecondSquared,
quantity => quantity.ToUnit(AccelerationUnit.NanometerPerSecondSquared), quantity => quantity.ToBaseUnit());
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared, AccelerationUnit.StandardGravity,
quantity => quantity.ToUnit(AccelerationUnit.StandardGravity), quantity => quantity.ToBaseUnit());
}
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.
Got it. I agree, the line became tough to read. The best I could come up with was:
unitConverter.SetConversionFunction<Acceleration>(AccelerationUnit.MeterPerSecondSquared,
AccelerationUnit.CentimeterPerSecondSquared,
quantity => quantity.ToUnit(AccelerationUnit.CentimeterPerSecondSquared),
quantity => quantity.ToBaseUnit());
Doesn't save vertical space though, so I don't know. I don't think it helps on neither the issue we are trying to fix nor readability. The code is also generated anyhow. LGTM!
.Wrap() | ||
.Assembly | ||
.GetExportedTypes() | ||
.Where(t => typeof(IQuantity).Wrap().IsAssignableFrom(t)); |
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 so much better to read 🙌
Nuget should be out shortly |
Move default unit converter registration to unit's static constructor.
Attempt to resolve #1016