I have a units of measure library that I added string formatting to. Here is sample code:

public void FormatSpeed()
    var speed = Speed.FromMetresPerSecond(1.2);
    using (Thread.CurrentThread.UsingTempCulture(CultureInfo.InvariantCulture))
        Assert.AreEqual("1.20\u00A0m/s", speed.ToString("F2"));
        Assert.AreEqual("1.20 m⋅s⁻¹", speed.ToString("F2 m⋅s⁻¹"));
        Assert.AreEqual("1.2\u00A0m/s", speed.ToString());
        Assert.AreEqual("1.2\u00A0m⋅s⁻¹", speed.ToString("m⋅s⁻¹"));
        Assert.AreEqual("1200\u00A0mm⋅s⁻¹", speed.ToString("mm⋅s⁻¹"));
        Assert.AreEqual("4.32\u00A0km/h", speed.ToString(SpeedUnit.KilometresPerHour));
        Assert.AreEqual("4.3\u00A0km/h", speed.ToString("F1", SpeedUnit.KilometresPerHour));

    var sv = CultureInfo.GetCultureInfo("sv-SE");
    Assert.AreEqual("1,20\u00A0m/s", speed.ToString("F2", sv));
    Assert.AreEqual("1,20 m⋅s⁻¹", speed.ToString("F2 m⋅s⁻¹", sv));
    Assert.AreEqual("1,2\u00A0m/s", speed.ToString(sv));
    Assert.AreEqual("1,2\u00A0m⋅s⁻¹", speed.ToString("m⋅s⁻¹", sv));
    Assert.AreEqual("1200\u00A0mm⋅s⁻¹", speed.ToString("mm⋅s⁻¹", sv));
    Assert.AreEqual("4,32\u00A0km/h", speed.ToString(SpeedUnit.KilometresPerHour, sv));
    Assert.AreEqual("4,3\u00A0km/h", speed.ToString("F1", SpeedUnit.KilometresPerHour, sv));

public void FormatAngle()
    var angle = Angle.FromDegrees(1.2);
    using (Thread.CurrentThread.UsingTempCulture(CultureInfo.InvariantCulture))
        Assert.AreEqual("0.020943951023932\u00A0rad", angle.ToString());
        Assert.AreEqual("1.200°", angle.ToString("F3°"));
        Assert.AreEqual("1.2°", angle.ToString(AngleUnit.Degrees));
        Assert.AreEqual(" 1.2 ° ", angle.ToString(" F1 ° "));
        Assert.AreEqual(" 0.02 rad", angle.ToString(" F2 "));
        Assert.AreEqual("1.200°", angle.ToString("F3", AngleUnit.Degrees));
        Assert.AreEqual("0.02\u00A0rad", angle.ToString("F2", AngleUnit.Radians));

    var sv = CultureInfo.GetCultureInfo("sv-SE");
    Assert.AreEqual("0,020943951023932\u00A0rad", angle.ToString(sv));
    Assert.AreEqual("1,200°", angle.ToString("F3°", sv));
    Assert.AreEqual("1,2°", angle.ToString(AngleUnit.Degrees, sv));
    Assert.AreEqual(" 1,2 ° ", angle.ToString(" F1 ° ", sv));
    Assert.AreEqual(" 0,02 rad", angle.ToString(" F2 ", sv));
    Assert.AreEqual("1,200°", angle.ToString("F3", AngleUnit.Degrees, sv));
    Assert.AreEqual("0,02\u00A0rad", angle.ToString("F2", AngleUnit.Radians, sv));

1) What overloads make sense and what are missing if any?

2) I'm really not sure about if adding composite formats like F2 m⋅s⁻¹ where F2 is for the scalar value and m⋅s⁻¹is for the unit is a good idea.

3) Is nobreaking space \u00A0 the best choice?

  • \$\begingroup\$ I'll remove or rework the composite formats as they are ambiguous: force.ToString("N"); Dunno why I did not think of that. Perhaps length.ToString("{0:N} {1:N}"); \$\endgroup\$ Nov 27, 2015 at 22:57

1 Answer 1


The only suggestion I would make is to extract each culture's tests to it's own unit tests. Each unit test should be testing one aspect of your code, whereas yours are each testing at least two.

Point 1: the only two overloads you need are .ToString(string) and .ToString(string, IFormatProvider). Everything else is just noise.

Point 2: you should not be adding composites like that, at all. It's just noise. If you really need that info to be passable to the .ToString call, then you should consider a third and fourth overload: .ToString(string format, string unit), and .ToString(string format, string unit, IFormatProvider formatProvider).

Point 3: I don't know enough about C# to be able to answer that exactly, but I would assume you should be using the literal space everywhere, or the \u00A0 everywhere. Pick one or the other, but don't mix-and-match.

Your unit tests have good content, but they need better names:

public void FormatSpeed_1p2_Invariant()
public void FormatSpeed_1p2_Sv_Se()
public void FormatAngle_1p2_Invariant()
public void FormatAngle_1p2_Sv_Se()

This makes it a little more clear as to what the tests are doing by name, so that when you look at the test explorer you can see you already have tests that cover certain aspects.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.