diff --git a/DataSizeUnits/DataSize.cs b/DataSizeUnits/DataSize.cs
index a98178f..f89bd73 100644
--- a/DataSizeUnits/DataSize.cs
+++ b/DataSizeUnits/DataSize.cs
@@ -9,13 +9,15 @@ namespace DataSizeUnits {
/// var kilobyte = new DataSize(1, Unit.Kilobyte);
///
[Serializable]
- public struct DataSize: IComparable {
+ public struct DataSize: IComparable, IFormattable {
public double Quantity;
public Unit Unit;
private double AsBits => Quantity * CountBitsInUnit(Unit);
+ private static readonly DataSizeFormatter Formatter = new DataSizeFormatter();
+
///
/// Create a new instance with the given quantity of the given unit of data.
/// var kilobyte = new DataSize(1, Unit.Kilobyte);
@@ -257,15 +259,29 @@ public override string ToString() {
///
/// Number of digits after the decimal place to use when formatting the quantity as a number. The
/// default for en-US is 2. To use the default for the current culture, pass the value -1, or call
- /// .
+ /// .
+ /// true to first normalize this instance to an automatically-chosen unit before converting it
+ /// to a string, or false (the default) to use the original unit this instance was defined with.
/// String with the formatted data quantity and unit abbreviation, separated by a space.
- public string ToString(int precision) {
- var culture = (CultureInfo) CultureInfo.CurrentCulture.Clone();
- if (precision >= 0) {
- culture.NumberFormat.NumberDecimalDigits = precision;
+ public string ToString(int precision, bool normalize = false) {
+ if (normalize) {
+ return Normalize(Unit.IsMultipleOfBits()).ToString(precision);
+ } else {
+ var culture = (CultureInfo) CultureInfo.CurrentCulture.Clone();
+ if (precision >= 0) {
+ culture.NumberFormat.NumberDecimalDigits = precision;
+ }
+
+ return Quantity.ToString("N", culture) + " " + Unit.ToAbbreviation();
}
+ }
+
+ public string ToString(string format, IFormatProvider formatProvider = null) {
+ return Formatter.Format(format, this, Formatter);
+ }
- return Quantity.ToString("N", culture) + " " + Unit.ToAbbreviation();
+ public string ToString(int precision, Unit unit) {
+ return ConvertToUnit(unit).ToString(precision);
}
public bool Equals(DataSize other) {
@@ -312,6 +328,14 @@ public int CompareTo(DataSize other) {
}
}
+ public static double operator /(DataSize a, DataSize b) {
+ if (!b.Quantity.Equals(0)) {
+ return a.AsBits / b.AsBits;
+ } else {
+ throw new DivideByZeroException();
+ }
+ }
+
public static bool operator ==(DataSize a, DataSize b) => a.Equals(b);
public static bool operator !=(DataSize a, DataSize b) => !a.Equals(b);
diff --git a/DataSizeUnits/DataSizeFormatter.cs b/DataSizeUnits/DataSizeFormatter.cs
index 0b8bcc3..3ff38ac 100644
--- a/DataSizeUnits/DataSizeFormatter.cs
+++ b/DataSizeUnits/DataSizeFormatter.cs
@@ -45,18 +45,21 @@ public string Format(string format, object arg, IFormatProvider formatProvider)
return null;
}
- DataSize dataSize;
- dataSize.Unit = Unit.Byte;
-
if (string.IsNullOrEmpty(format)) {
format = DefaultFormat;
}
- try {
- long bytes = Convert.ToInt64(arg);
- dataSize.Quantity = bytes;
- } catch (Exception) {
- return HandleOtherFormats(format, arg);
+ DataSize dataSize;
+ if (arg is DataSize size) {
+ dataSize = size;
+ } else {
+ dataSize.Unit = Unit.Byte;
+ try {
+ long bytes = Convert.ToInt64(arg);
+ dataSize.Quantity = bytes;
+ } catch (Exception) {
+ return HandleOtherFormats(format, arg);
+ }
}
string unitString = Regex.Match(format, @"^[a-z]+", RegexOptions.IgnoreCase).Value;
diff --git a/DataSizeUnits/DataSizeUnits.csproj b/DataSizeUnits/DataSizeUnits.csproj
index b39b409..1dbaaff 100644
--- a/DataSizeUnits/DataSizeUnits.csproj
+++ b/DataSizeUnits/DataSizeUnits.csproj
@@ -4,10 +4,11 @@
netstandard2.0
2.1.0
Ben Hutchison
+ Ben Hutchison
DataSizeUnits
DataSizeUnits
Convert and format data size units in .NET (bits, bytes, kilobits, kilobytes, and others).
- 2020 Ben Hutchison
+ 2021 Ben Hutchison
https://github.com/Aldaviva/DataSizeUnits
https://github.com/Aldaviva/DataSizeUnits.git
git
diff --git a/DataSizeUnits/Unit.cs b/DataSizeUnits/Unit.cs
index c49238d..61a4619 100644
--- a/DataSizeUnits/Unit.cs
+++ b/DataSizeUnits/Unit.cs
@@ -88,7 +88,7 @@ public static class UnitExtensions {
/// true to return the IEC abbreviation (KiB, MiB, etc.), or false (the default) to return
/// the JEDEC abbreviation (KB, MB, etc.)
/// The abbreviation for this unit.
- public static string ToAbbreviation(this Unit unit, bool iec=false) {
+ public static string ToAbbreviation(this Unit unit, bool iec = false) {
switch (unit) {
case Unit.Byte:
return "B";
@@ -169,6 +169,31 @@ public static string ToName(this Unit unit, bool iec = false) {
}
}
+ public static bool IsMultipleOfBits(this Unit unit) {
+ switch (unit) {
+ case Unit.Byte:
+ case Unit.Kilobyte:
+ case Unit.Megabyte:
+ case Unit.Gigabyte:
+ case Unit.Terabyte:
+ case Unit.Petabyte:
+ case Unit.Exabyte:
+ return false;
+
+ case Unit.Bit:
+ case Unit.Kilobit:
+ case Unit.Megabit:
+ case Unit.Gigabit:
+ case Unit.Terabit:
+ case Unit.Petabit:
+ case Unit.Exabit:
+ return true;
+
+ default:
+ throw new ArgumentOutOfRangeException(nameof(unit), unit, null);
+ }
+ }
+
public static DataSize Quantity(this Unit unit, double quantity) {
return new DataSize(quantity, unit);
}
diff --git a/Tests/DataSizeFormatterTests.cs b/Tests/DataSizeFormatterTests.cs
index b0cfd72..952efa6 100644
--- a/Tests/DataSizeFormatterTests.cs
+++ b/Tests/DataSizeFormatterTests.cs
@@ -1,4 +1,5 @@
using System;
+using System.Globalization;
using DataSizeUnits;
using Xunit;
@@ -12,11 +13,11 @@ public class DataSizeFormatterTests {
[MemberData(nameof(UnitData))]
public void FormatUsingCustomFormatter(ulong inputBytes, string formatSyntax, string expectedOutput) {
string formatString = "{0:" + formatSyntax + "}";
- string actual = string.Format(new DataSizeFormatter(), formatString, inputBytes);
+ string actual = string.Format(new DataSizeFormatter(), formatString, inputBytes);
Assert.Equal(expectedOutput, actual);
}
- public static TheoryData FormatData = new TheoryData {
+ public static TheoryData FormatData = new() {
{ 0, "", "0.00 B" },
{ 0, "A", "0.00 B" },
{ 1024, "A", "1.00 KB" },
@@ -28,7 +29,7 @@ public void FormatUsingCustomFormatter(ulong inputBytes, string formatSyntax, st
{ 1024L * 1024 * 1024 * 1024 * 1024 * 1024, "A", "1.00 EB" }
};
- public static TheoryData PrecisionData = new TheoryData {
+ public static TheoryData PrecisionData = new() {
{ 9_995_326_316_544, "A", "9.09 TB" },
{ 9_995_326_316_544, "A0", "9 TB" },
{ 9_995_326_316_544, "1", "9.1 TB" },
@@ -37,7 +38,7 @@ public void FormatUsingCustomFormatter(ulong inputBytes, string formatSyntax, st
{ 9_995_326_316_544, "A3", "9.091 TB" }
};
- public static TheoryData UnitData = new TheoryData {
+ public static TheoryData UnitData = new() {
{ 9_995_326_316_544, "B0", "9,995,326,316,544 B" },
{ 9_995_326_316_544, "K0", "9,761,060,856 KB" },
{ 9_995_326_316_544, "KB0", "9,761,060,856 KB" },
@@ -82,13 +83,31 @@ public void ConvertAndFormatUsingToString() {
Assert.Equal("1.41 MB", actual);
}
- [Theory, MemberData(nameof(OtherData))]
+ [Fact]
+ public void FormatUsingToStringAndFormatProvider() {
+ string actual = new DataSize(1474560).ToString("K1", CultureInfo.CurrentCulture);
+ Assert.Equal("1,440.0 KB", actual);
+ }
+
+ [Fact]
+ public void FormatUsingPrecisionAndUnit() {
+ string actual = new DataSize(1474560).ToString(2, Unit.Kilobyte);
+ Assert.Equal("1,440.00 KB", actual);
+ }
+
+ [Fact]
+ public void FormatUsingToStringAndNormalize() {
+ string actual = new DataSize(1474560).ToString(2, true);
+ Assert.Equal("1.41 MB", actual);
+ }
+
+ [Theory] [MemberData(nameof(OtherData))]
public void HandleOtherFormats(object otherInput, string expectedOutput) {
string actualOutput = string.Format(new DataSizeFormatter(), "{0:D}", otherInput);
Assert.Equal(expectedOutput, actualOutput);
}
- public static TheoryData