Created
May 18, 2012 16:15
-
-
Save josheinstein/2726144 to your computer and use it in GitHub Desktop.
DataSize Class (C#)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.ComponentModel; | |
using System.Diagnostics.CodeAnalysis; | |
using System.Diagnostics.Contracts; | |
using System.Globalization; | |
using System.Linq; | |
using System.Text.RegularExpressions; | |
using System.Xml.Serialization; | |
namespace Einstein | |
{ | |
/// <summary> | |
/// A structure for representing sizes in bytes, KB, MB, etc while retaining the full value type | |
/// nature of a native structure. A value of type DataSize sorts correctly in lists, chooses its | |
/// unit automatically similar to how Windows Explorer does, and can be used with standard | |
/// operators such as adding, subtracting, greater than/less than, etc. It can be quickly and | |
/// implicitly cast to and from bytes (Int64) and implements various interfaces that make it | |
/// nearly a first-class data structure like DateTime. | |
/// </summary> | |
[Serializable] | |
public struct DataSize : IFormattable, IComparable<DataSize>, IComparable, IConvertible, IEquatable<DataSize>, IXmlSerializable | |
{ | |
#region Constants | |
/// <summary> | |
/// The size of a byte, in bytes. Always 1, provided for consistency only. | |
/// </summary> | |
public const long ByteSize = 1L; | |
/// <summary> | |
/// The size of a kilobyte, in bytes. This structure defines a KB as 1,024 bytes. | |
/// </summary> | |
public const long KilobyteSize = 1024L; | |
/// <summary> | |
/// The size of a megabyte, in bytes. This structure defines a MB as 1,024^2 or 1,048,576 bytes. | |
/// </summary> | |
public const long MegabyteSize = 1024L * 1024L; | |
/// <summary> | |
/// The size of a gigabyte, in bytes. This structure defines a GB as 1,024^3 or 1,073,741,824 bytes. | |
/// </summary> | |
public const long GigabyteSize = 1024L * 1024L * 1024L; | |
/// <summary> | |
/// The size of a terabyte, in bytes. This structure defines a TB as 1,024^4 or 1,099,511,627,776 bytes. | |
/// </summary> | |
public const long TerabyteSize = 1024L * 1024L * 1024L * 1024L; | |
/// <summary> | |
/// The suffix appended to the end of a string represented as bytes. | |
/// </summary> | |
public const string ByteSuffix = "B"; | |
/// <summary> | |
/// The suffix appended to the end of a string represented as kilobytes. | |
/// </summary> | |
public const string KilobyteSuffix = "KB"; | |
/// <summary> | |
/// The suffix appended to the end of a string represented as megabytes. | |
/// </summary> | |
public const string MegabyteSuffix = "MB"; | |
/// <summary> | |
/// The suffix appended to the end of a string represented as gigabytes. | |
/// </summary> | |
public const string GigabyteSuffix = "GB"; | |
/// <summary> | |
/// The suffix appended to the end of a string represented as terabytes. | |
/// </summary> | |
public const string TerabyteSuffix = "TB"; | |
#endregion | |
#region Fields | |
/// <summary> | |
/// Holds the value of the data size, in bytes. | |
/// </summary> | |
private long bytes; | |
/// <summary> | |
/// Regular expression used to pick apart the format string. | |
/// </summary> | |
private static readonly Regex formatRegex = new Regex( @"(?<unit>A|B|K|M|G|T)(?<precision>\d+)?(?<nosuffix>\*)?", RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase | RegexOptions.Singleline ); | |
#endregion | |
#region Constructors | |
/// <summary> | |
/// Creates a new DataSize representing the specified number of bytes. | |
/// </summary> | |
public DataSize( long bytes ) | |
{ | |
this.bytes = bytes; | |
} | |
#endregion | |
#region Properties | |
/// <summary> | |
/// Gets the value in terabytes. | |
/// </summary> | |
public decimal TotalTerabytes | |
{ | |
get | |
{ | |
return bytes / (decimal)TerabyteSize; | |
} | |
} | |
/// <summary> | |
/// Gets the value in gigabytes. | |
/// </summary> | |
public decimal TotalGigabytes | |
{ | |
get | |
{ | |
return bytes / (decimal)GigabyteSize; | |
} | |
} | |
/// <summary> | |
/// Gets the value in megabytes. | |
/// </summary> | |
public decimal TotalMegabytes | |
{ | |
get | |
{ | |
return bytes / (decimal)MegabyteSize; | |
} | |
} | |
/// <summary> | |
/// Gets the value in kilobytes. | |
/// </summary> | |
public decimal TotalKilobytes | |
{ | |
get | |
{ | |
return bytes / (decimal)KilobyteSize; | |
} | |
} | |
/// <summary> | |
/// Gets the value in bytes. | |
/// </summary> | |
public decimal TotalBytes | |
{ | |
get | |
{ | |
return (decimal)bytes; | |
} | |
} | |
/// <summary> | |
/// Gets the value in bytes as a signed 64 bit integer. | |
/// </summary> | |
public long Bytes | |
{ | |
get | |
{ | |
return bytes; | |
} | |
} | |
#endregion | |
#region Methods | |
/// <summary> | |
/// Converts the String representation of a number to its DataSize equivalent. A return value indicates whether the conversion succeeded or failed. | |
/// </summary> | |
/// <remarks> | |
/// <para> | |
/// The string can take on the format of: | |
/// <list type="bullet"> | |
/// <item>128 MB</item> | |
/// <item>40.00 KB</item> | |
/// <item>78 gigabytes</item> | |
/// <item>1 terabyte</item> | |
/// </list> | |
/// </para> | |
/// <para> | |
/// Lowercase representations will be accepted such as a b, kb, mb, etc but they will not be treated as "bits" they | |
/// will be treated as "bytes". Their acceptance is simply to keep the function case insensitive. | |
/// </para> | |
/// </remarks> | |
/// <param name="input">A String object containing a data size to convert.</param> | |
/// <returns>A DataSize structure representing the specified string.</returns> | |
public static DataSize Parse( string input ) | |
{ | |
if ( input == null ) | |
throw new ArgumentNullException( "input" ); | |
DataSize dataSize; | |
if ( TryParse( input, out dataSize ) ) | |
return dataSize; | |
else | |
throw new FormatException( "Could not parse the specified string into a DataSize." ); | |
} | |
/// <summary> | |
/// Converts the String representation of a number to its DataSize equivalent. A return value indicates whether the conversion succeeded or failed. | |
/// </summary> | |
/// <param name="input">A String object containing a number to convert.</param> | |
/// <param name="dataSize">When this method returns, contains DatSize equivalent to the numeric value or symbol contained | |
/// in input, if the conversion succeeded, or zero if the conversion failed. The conversion fails if the input parameter is a null | |
/// reference (Nothing in Visual Basic), is not a number in a valid format, or represents a number less than MinValue or greater than MaxValue. This | |
/// parameter is passed uninitialized.</param> | |
/// <returns> | |
/// True if the parse succeeded, false otherwise. | |
/// </returns> | |
/// <remarks> | |
/// <para> | |
/// The string can take on the format of: | |
/// <list type="bullet"> | |
/// <item>128 MB</item> | |
/// <item>40.00 KB</item> | |
/// <item>78 gigabytes</item> | |
/// <item>1 terabyte</item> | |
/// </list> | |
/// </para> | |
/// <para> | |
/// Lowercase representations will be accepted such as a b, kb, mb, etc but they will not be treated as "bits" they | |
/// will be treated as "bytes". Their acceptance is simply to keep the function case insensitive. | |
/// </para> | |
/// </remarks> | |
public static bool TryParse( string input, out DataSize dataSize ) | |
{ | |
return TryParse( input, false, out dataSize ); | |
} | |
/// <summary> | |
/// Converts the String representation of a number to its DataSize equivalent. A return value indicates whether the conversion succeeded or failed. | |
/// </summary> | |
/// <param name="input">A String object containing a number to convert.</param> | |
/// <param name="requireUnit">True if a data size unit is required for the parse to succeed, false otherwise.</param> | |
/// <param name="dataSize">When this method returns, contains DatSize equivalent to the numeric value or symbol contained | |
/// in input, if the conversion succeeded, or zero if the conversion failed. The conversion fails if the input parameter is a null | |
/// reference (Nothing in Visual Basic), is not a number in a valid format, or represents a number less than MinValue or greater than MaxValue. This | |
/// parameter is passed uninitialized.</param> | |
/// <returns> | |
/// True if the parse succeeded, false otherwise. | |
/// </returns> | |
/// <remarks> | |
/// <para> | |
/// The string can take on the format of: | |
/// <list type="bullet"> | |
/// <item>128 MB</item> | |
/// <item>40.00 KB</item> | |
/// <item>78 gigabytes</item> | |
/// <item>1 terabyte</item> | |
/// </list> | |
/// </para> | |
/// <para> | |
/// Lowercase representations will be accepted such as a b, kb, mb, etc but they will not be treated as "bits" they | |
/// will be treated as "bytes". Their acceptance is simply to keep the function case insensitive. | |
/// </para> | |
/// </remarks> | |
[SuppressMessage( "Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "The switch statement is throwing it off." )] | |
public static bool TryParse( string input, bool requireUnit, out DataSize dataSize ) | |
{ | |
dataSize = default( DataSize ); | |
// Make sure we have a string | |
if ( String.IsNullOrEmpty( input ) ) | |
return false; | |
// Trim both ends of input | |
input = input.Trim( ); | |
string numberPart = null; | |
string unitPart = null; | |
// Find the position of the space, if any | |
int spacePos = input.IndexOf( ' ' ); | |
if ( spacePos > -1 ) { | |
// A space exists in the string | |
// First segment is the number such as 3.04 | |
// Second segment is assumed to be the unit such as KB | |
numberPart = input.Substring( 0, spacePos ).Trim( ); | |
unitPart = input.Substring( spacePos + 1 ).Trim( ); | |
} | |
else { | |
if ( requireUnit ) { | |
return false; | |
} | |
else { | |
numberPart = input; | |
unitPart = "B"; | |
} | |
} | |
// Parse the number into a decimal. Allow separators and such | |
// If the parse fails, an exception will be thrown which will | |
// propagate out to the caller. | |
decimal number = 0m; | |
if ( Decimal.TryParse( numberPart, NumberStyles.Number, null, out number ) ) { | |
#region B.A.S.S. - Big Ass Switch Statement | |
switch ( unitPart.ToUpper( CultureInfo.InvariantCulture ) ) { | |
case "B": | |
case "BYTE": | |
case "BYTES": | |
break; | |
case "K": | |
case "KB": | |
case "KBYTE": | |
case "KBYTES": | |
case "KILOBYTE": | |
case "KILOBYTES": | |
number *= KilobyteSize; | |
break; | |
case "M": | |
case "MB": | |
case "MEG": | |
case "MEGS": | |
case "MBYTE": | |
case "MBYTES": | |
case "MEGABYTE": | |
case "MEGABYTES": | |
number *= MegabyteSize; | |
break; | |
case "G": | |
case "GB": | |
case "GIG": | |
case "GIGS": | |
case "GBYTE": | |
case "GBYTES": | |
case "GIGABYTE": | |
case "GIGABYTES": | |
number *= GigabyteSize; | |
break; | |
case "T": | |
case "TB": | |
case "TBYTE": | |
case "TBYTES": | |
case "TERABYTE": | |
case "TERABYTES": | |
number *= TerabyteSize; | |
break; | |
default: | |
return false; | |
} | |
#endregion | |
dataSize = new DataSize( (long)number ); | |
return true; | |
} | |
return false; | |
} | |
/// <summary> | |
/// Compares two DataSize structures and returns a value indicating whether one is less | |
/// than, equal to, or greater than the other. | |
/// </summary> | |
/// <param name="x">The first DataSize to compare.</param> | |
/// <param name="y">The second DataSize to compare.</param> | |
/// <returns> | |
/// Less than zero, x is less than y. Zero, x equals y. Greater than zero, x is greater than y. | |
/// </returns> | |
[SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "x" )] | |
[SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "y" )] | |
public static int Compare( DataSize x, DataSize y ) | |
{ | |
return x.CompareTo( y ); | |
} | |
/// <summary> | |
/// Determines of two DataSize values are equal. | |
/// </summary> | |
/// <param name="x">The first DataSize to compare.</param> | |
/// <param name="y">The second DataSize to compare.</param> | |
/// <returns>True if the values are equal, false otherwise.</returns> | |
[SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "x" )] | |
[SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "y" )] | |
public static bool Equals( DataSize x, DataSize y ) | |
{ | |
return x.Equals( y ); | |
} | |
#endregion | |
#region Object Overrides | |
/// <summary> | |
/// Indicates whether this instance and a specified object are equal. | |
/// </summary> | |
/// <param name="obj">Another object to compare to.</param> | |
/// <returns> | |
/// true if obj and this instance are the same type and represent the same value; otherwise, false. | |
/// </returns> | |
public override bool Equals( object obj ) | |
{ | |
if ( obj is DataSize ) | |
return Equals( (DataSize)obj ); | |
else | |
return false; | |
} | |
/// <summary> | |
/// Returns the hash code for this instance. | |
/// </summary> | |
/// <returns> | |
/// A 32-bit signed integer that is the hash code for this instance. | |
/// </returns> | |
public override int GetHashCode( ) | |
{ | |
return bytes.GetHashCode( ); | |
} | |
/// <summary> | |
/// Returns a string representation of this DataSize using the default format. | |
/// </summary> | |
/// <returns> | |
/// A <see cref="T:String"></see> representing this data size. | |
/// </returns> | |
public override string ToString( ) | |
{ | |
return ToString( "A", CultureInfo.CurrentCulture ); | |
} | |
/// <summary> | |
/// Returns a string representation of this DataSize using the default format. | |
/// </summary> | |
/// <param name="format">The format.</param> | |
/// <returns> | |
/// A <see cref="T:String"></see> representing this data size. | |
/// </returns> | |
/// <remarks> | |
/// <para> | |
/// The format specifier takes the form of: A99* | |
/// </para> | |
/// <para> | |
/// Where A is any of the following characters: | |
/// <list type="table"> | |
/// <listheader><term>Format Character</term></listheader> | |
/// <item><term>A</term><description>Automatic. The unit of measurement will be the largest unit that is greater than or equal to 1.</description></item> | |
/// <item><term>B</term><description>Bytes (B). No decimal digits will ever be displayed.</description></item> | |
/// <item><term>K</term><description>Kilobytes (KB)</description></item> | |
/// <item><term>M</term><description>Megabytes (MB)</description></item> | |
/// <item><term>G</term><description>Gigabytes (GB)</description></item> | |
/// <item><term>T</term><description>Terabytes (TB)</description></item> | |
/// </list> | |
/// </para> | |
/// <para> | |
/// The 99 represent a number from 0-99 that indicates the number of decimal places that will be | |
/// included in the string. If bytes are specified as the unit of measurement, no decimal places will | |
/// ever be used and this part of the format string will be ignored. If the precision is missing, up | |
/// to two decimal places will be used. | |
/// </para> | |
/// <para> | |
/// The asterisk (*) is an optional indicator that supresses the suffix. For example, if the value 39 KB | |
/// is formatted as "K2*" then the output string would be "39.00" instead of "39.00 KB" because of the | |
/// asterisk. | |
/// </para> | |
/// </remarks> | |
public string ToString( string format ) | |
{ | |
return ToString( format, CultureInfo.CurrentCulture ); | |
} | |
#endregion | |
#region Operator Overloads | |
/// <summary> | |
/// Equality operator. | |
/// </summary> | |
/// <param name="left">The first DataSize to compare.</param> | |
/// <param name="right">The second DataSize to compare.</param> | |
/// <returns>True if <paramref name="left"/> and <paramref name="right"/> are equal, false otherwise.</returns> | |
public static bool operator ==( DataSize left, DataSize right ) | |
{ | |
return left.bytes == right.bytes; | |
} | |
/// <summary> | |
/// Inequality operator. | |
/// </summary> | |
/// <param name="left">The first DataSize to compare.</param> | |
/// <param name="right">The second DataSize to compare.</param> | |
/// <returns>False if <paramref name="left"/> and <paramref name="right"/> are equal, true otherwise.</returns> | |
public static bool operator !=( DataSize left, DataSize right ) | |
{ | |
return left.bytes != right.bytes; | |
} | |
/// <summary> | |
/// Greater than operator. | |
/// </summary> | |
/// <param name="left">The first DataSize to compare.</param> | |
/// <param name="right">The second DataSize to compare.</param> | |
/// <returns>True if <paramref name="left"/> is greater than <paramref name="right"/>, false otherwise.</returns> | |
public static bool operator >( DataSize left, DataSize right ) | |
{ | |
return left.bytes > right.bytes; | |
} | |
/// <summary> | |
/// Less than operator. | |
/// </summary> | |
/// <param name="left">The first DataSize to compare.</param> | |
/// <param name="right">The second DataSize to compare.</param> | |
/// <returns>True if <paramref name="left"/> is less than <paramref name="right"/>, false otherwise.</returns> | |
public static bool operator <( DataSize left, DataSize right ) | |
{ | |
return left.bytes < right.bytes; | |
} | |
/// <summary> | |
/// Greater than or equals operator. | |
/// </summary> | |
/// <param name="left">The first DataSize to compare.</param> | |
/// <param name="right">The second DataSize to compare.</param> | |
/// <returns>True if <paramref name="left"/> is greater than or equals <paramref name="right"/>, false otherwise.</returns> | |
public static bool operator >=( DataSize left, DataSize right ) | |
{ | |
return left.bytes >= right.bytes; | |
} | |
/// <summary> | |
/// Less than or equals operator. | |
/// </summary> | |
/// <param name="left">The first DataSize to compare.</param> | |
/// <param name="right">The second DataSize to compare.</param> | |
/// <returns>True if <paramref name="left"/> is less than or equals <paramref name="right"/>, false otherwise.</returns> | |
public static bool operator <=( DataSize left, DataSize right ) | |
{ | |
return left.bytes <= right.bytes; | |
} | |
/// <summary> | |
/// Unary plus operator. | |
/// </summary> | |
/// <param name="operand">The operand on which the operator operates.</param> | |
/// <returns>The <paramref name="operand"/>.</returns> | |
public static DataSize operator +( DataSize operand ) | |
{ | |
return operand; | |
} | |
/// <summary> | |
/// Unary negation operator. | |
/// </summary> | |
/// <param name="operand">The operand on which the operator operates.</param> | |
/// <returns>The <paramref name="operand"/>, negated.</returns> | |
public static DataSize operator -( DataSize operand ) | |
{ | |
return new DataSize( -( operand.bytes ) ); | |
} | |
/// <summary> | |
/// Unary increment operator. | |
/// </summary> | |
/// <param name="operand">The operand on which the operator operates.</param> | |
/// <returns>The <paramref name="operand"/> plus one.</returns> | |
public static DataSize operator ++( DataSize operand ) | |
{ | |
return new DataSize( operand.bytes + 1 ); | |
} | |
/// <summary> | |
/// Unary decrement operator. | |
/// </summary> | |
/// <param name="operand">The operand on which the operator operates.</param> | |
/// <returns>The <paramref name="operand"/>, minus one.</returns> | |
public static DataSize operator --( DataSize operand ) | |
{ | |
return new DataSize( operand.bytes - 1 ); | |
} | |
/// <summary> | |
/// Addition operator. | |
/// </summary> | |
/// <param name="left">A DataSize to which <paramref name="right"/> will be added.</param> | |
/// <param name="right">A second DataSize to add to <paramref name="left"/>.</param> | |
/// <returns>A datasize that is the sum of <paramref name="left"/> and <paramref name="right"/>.</returns> | |
public static DataSize operator +( DataSize left, DataSize right ) | |
{ | |
return new DataSize( left.bytes + right.bytes ); | |
} | |
/// <summary> | |
/// Subtraction operator. | |
/// </summary> | |
/// <param name="left">A DataSize to which <paramref name="right"/> will be subtracted.</param> | |
/// <param name="right">A second DataSize to subtract from <paramref name="left"/>.</param> | |
/// <returns>A datasize that is the difference of <paramref name="left"/> and <paramref name="right"/>.</returns> | |
public static DataSize operator -( DataSize left, DataSize right ) | |
{ | |
return new DataSize( left.bytes - right.bytes ); | |
} | |
/// <summary> | |
/// Multiplication operator. | |
/// </summary> | |
/// <param name="left">A DataSize which will be multiplied by <paramref name="right"/>.</param> | |
/// <param name="right">A DataSize by which <paramref name="left"/> will be multiplied.</param> | |
/// <returns>A datasize that is the result of <paramref name="left"/> multiplied by <paramref name="right"/>.</returns> | |
public static DataSize operator *( DataSize left, DataSize right ) | |
{ | |
return new DataSize( left.bytes * right.bytes ); | |
} | |
/// <summary> | |
/// Division operator. | |
/// </summary> | |
/// <param name="left">A DataSize which will be divided by <paramref name="right"/>.</param> | |
/// <param name="right">A DataSize by which <paramref name="left"/> will be divided.</param> | |
/// <returns>A datasize that is the result of <paramref name="left"/> divided by <paramref name="right"/>.</returns> | |
public static DataSize operator /( DataSize left, DataSize right ) | |
{ | |
return new DataSize( left.bytes / right.bytes ); | |
} | |
#endregion | |
#region Conversion Operators | |
/// <summary> | |
/// Implicitly converts the specified <paramref name="operand"/> to <see cref="Int64"/>. | |
/// </summary> | |
/// <param name="operand">The DataSize to convert.</param> | |
/// <returns>An <see cref="Int64"/> value that is the number of bytes represented by | |
/// <paramref name="operand"/>.</returns> | |
public static implicit operator long( DataSize operand ) | |
{ | |
return operand.bytes; | |
} | |
/// <summary> | |
/// Implicitly converts the specified <paramref name="operand"/> to <see cref="Decimal"/>. | |
/// </summary> | |
/// <param name="operand">The DataSize to convert.</param> | |
/// <returns>A <see cref="Decimal"/> value that is the number of bytes represented by | |
/// <paramref name="operand"/>.</returns> | |
public static implicit operator decimal( DataSize operand ) | |
{ | |
return operand.TotalBytes; | |
} | |
/// <summary> | |
/// Explicitly converts the specified <paramref name="operand"/> to <see cref="DataSize"/>. | |
/// </summary> | |
/// <param name="operand">The <see cref="Int64"/> to convert.</param> | |
/// <returns>A <see cref="DataSize"/> value that represents <paramref name="operand"/> | |
/// number of bytes.</returns> | |
[SuppressMessage( "Microsoft.Interoperability", "CA1406:AvoidInt64ArgumentsForVB6Clients", Justification = "VB 6 can't use overloaded operators." )] | |
public static explicit operator DataSize( long operand ) | |
{ | |
return new DataSize( operand ); | |
} | |
/// <summary> | |
/// Explicitly converts the specified <paramref name="operand"/> to a string. | |
/// </summary> | |
/// <param name="operand">The <see cref="DataSize"/> to convert.</param> | |
/// <returns> | |
/// A string value that is the same as <see cref="M:ToString"/>. | |
/// </returns> | |
public static explicit operator string( DataSize operand ) | |
{ | |
return operand.ToString( ); | |
} | |
#endregion | |
#region IFormattable Members | |
/// <summary> | |
/// Formats the value of the current instance using the specified format. | |
/// </summary> | |
/// <param name="format">The <see cref="T:String"></see> specifying the format to use.-or- null to use the default format defined for the type of the <see cref="T:IFormattable"></see> implementation.</param> | |
/// <param name="formatProvider">The <see cref="T:IFormatProvider"></see> to use to format the value.-or- null to obtain the numeric format information from the current locale setting of the operating system.</param> | |
/// <returns> | |
/// A <see cref="T:String"></see> containing the value of the current instance in the specified format. | |
/// </returns> | |
public string ToString( string format, IFormatProvider formatProvider ) | |
{ | |
if ( String.IsNullOrEmpty( format ) ) { | |
format = "A"; | |
} | |
Match formatMatch = formatRegex.Match( format ); | |
if ( formatMatch.Success ) { | |
decimal value; | |
int precision; | |
string suffix; | |
// Parse the precision specifier which determines how many decimal digits | |
// will be displayed in the number portion of the return value. | |
if ( formatMatch.Groups["precision"].Success ) { | |
// Try to parse the precision specifier and if we can't, default to zero | |
if ( Int32.TryParse( formatMatch.Groups["precision"].Value, out precision ) ) { | |
if ( precision > 99 || precision < 0 ) { | |
throw new FormatException( "Invalid format specifier." ); | |
} | |
} | |
else { | |
throw new FormatException( "Invalid format specifier." ); | |
} | |
} | |
else { | |
precision = 2; | |
} | |
switch ( formatMatch.Groups["unit"].Value.ToUpper( CultureInfo.InvariantCulture ) ) { | |
case "A": { | |
// Automatic based on the size of the value | |
if ( Decimal.Truncate( Math.Abs( TotalTerabytes ) ) >= 1 ) { | |
goto case "T"; | |
} | |
else if ( Decimal.Truncate( Math.Abs( TotalGigabytes ) ) >= 1 ) { | |
goto case "G"; | |
} | |
else if ( Decimal.Truncate( Math.Abs( TotalMegabytes ) ) >= 1 ) { | |
goto case "M"; | |
} | |
else if ( Decimal.Truncate( Math.Abs( TotalKilobytes ) ) >= 1 ) { | |
goto case "K"; | |
} | |
else { | |
goto case "B"; | |
} | |
} | |
case "B": { | |
value = TotalBytes; | |
suffix = ByteSuffix; | |
precision = 0; // bytes cannot be fractional | |
break; | |
} | |
case "K": { | |
value = TotalKilobytes; | |
suffix = KilobyteSuffix; | |
break; | |
} | |
case "M": { | |
value = TotalMegabytes; | |
suffix = MegabyteSuffix; | |
break; | |
} | |
case "G": { | |
value = TotalGigabytes; | |
suffix = GigabyteSuffix; | |
break; | |
} | |
case "T": { | |
value = TotalTerabytes; | |
suffix = TerabyteSuffix; | |
break; | |
} | |
default: { | |
throw new FormatException( "Invalid format specifier." ); | |
} | |
} | |
if ( formatMatch.Groups["nosuffix"].Success ) { | |
// They want the value without the suffix | |
return String.Format( formatProvider, "{0:N" + precision + "}", value ); | |
} | |
else { | |
// They want the value with the sufffix | |
return String.Format( formatProvider, "{0:N" + precision + "} {1}", value, suffix ); | |
} | |
} | |
else { | |
throw new FormatException( "Invalid format specifier." ); | |
} | |
} | |
#endregion | |
#region IComparable<DataSize> Members | |
/// <summary> | |
/// Compares the current object with another object of the same type. | |
/// </summary> | |
/// <param name="other">An object to compare with this object.</param> | |
/// <returns> | |
/// A 32-bit signed integer that indicates the relative order of the objects being compared. The return value has the following meanings: Value Meaning Less than zero This object is less than the other parameter.Zero This object is equal to other. Greater than zero This object is greater than other. | |
/// </returns> | |
public int CompareTo( DataSize other ) | |
{ | |
return bytes.CompareTo( other.bytes ); | |
} | |
#endregion | |
#region IComparable Members | |
/// <summary> | |
/// Compares the current instance with another object of the same type. | |
/// </summary> | |
/// <param name="obj">An object to compare with this instance.</param> | |
/// <returns> | |
/// A 32-bit signed integer that indicates the relative order of the objects being compared. The return value has these meanings: Value Meaning Less than zero This instance is less than obj. Zero This instance is equal to obj. Greater than zero This instance is greater than obj. | |
/// </returns> | |
/// <exception cref="T:ArgumentException">obj is not the same type as this instance. </exception> | |
public int CompareTo( object obj ) | |
{ | |
if ( obj is DataSize ) { | |
return CompareTo( (DataSize)obj ); | |
} | |
else { | |
throw new ArgumentException( "Compared value is not a DataSize.", "obj" ); | |
} | |
} | |
#endregion | |
#region IConvertible Members | |
/// <summary> | |
/// Returns the <see cref="T:TypeCode"></see> for this instance. | |
/// </summary> | |
/// <returns> | |
/// The enumerated constant that is the <see cref="T:TypeCode"></see> of the class or value type that implements this interface. | |
/// </returns> | |
TypeCode IConvertible.GetTypeCode( ) | |
{ | |
return TypeCode.Int64; | |
} | |
/// <summary> | |
/// Converts the value of this instance to an equivalent Boolean value using the specified culture-specific formatting information. | |
/// </summary> | |
/// <param name="provider">An <see cref="T:IFormatProvider"></see> interface implementation that supplies culture-specific formatting information.</param> | |
/// <returns> | |
/// A Boolean value equivalent to the value of this instance. | |
/// </returns> | |
bool IConvertible.ToBoolean( IFormatProvider provider ) | |
{ | |
return ( bytes != 0 ); | |
} | |
/// <summary> | |
/// Converts the value of this instance to an equivalent 8-bit unsigned integer using the specified culture-specific formatting information. | |
/// </summary> | |
/// <param name="provider">An <see cref="T:IFormatProvider"></see> interface implementation that supplies culture-specific formatting information.</param> | |
/// <returns> | |
/// An 8-bit unsigned integer equivalent to the value of this instance. | |
/// </returns> | |
byte IConvertible.ToByte( IFormatProvider provider ) | |
{ | |
return (byte)bytes; | |
} | |
/// <summary> | |
/// Converts the value of this instance to an equivalent Unicode character using the specified culture-specific formatting information. | |
/// </summary> | |
/// <param name="provider">An <see cref="T:IFormatProvider"></see> interface implementation that supplies culture-specific formatting information.</param> | |
/// <returns> | |
/// A Unicode character equivalent to the value of this instance. | |
/// </returns> | |
char IConvertible.ToChar( IFormatProvider provider ) | |
{ | |
throw new InvalidCastException( "Cannot convert from Einstein.DataSize to System.Char." ); | |
} | |
/// <summary> | |
/// Converts the value of this instance to an equivalent <see cref="T:DateTime"></see> using the specified culture-specific formatting information. | |
/// </summary> | |
/// <param name="provider">An <see cref="T:IFormatProvider"></see> interface implementation that supplies culture-specific formatting information.</param> | |
/// <returns> | |
/// A <see cref="T:DateTime"></see> instance equivalent to the value of this instance. | |
/// </returns> | |
DateTime IConvertible.ToDateTime( IFormatProvider provider ) | |
{ | |
throw new InvalidCastException( "Cannot convert from Einstein.DataSize to System.DateTime." ); | |
} | |
/// <summary> | |
/// Converts the value of this instance to an equivalent <see cref="T:Decimal"></see> number using the specified culture-specific formatting information. | |
/// </summary> | |
/// <param name="provider">An <see cref="T:IFormatProvider"></see> interface implementation that supplies culture-specific formatting information.</param> | |
/// <returns> | |
/// A <see cref="T:Decimal"></see> number equivalent to the value of this instance. | |
/// </returns> | |
decimal IConvertible.ToDecimal( IFormatProvider provider ) | |
{ | |
return (decimal)bytes; | |
} | |
/// <summary> | |
/// Converts the value of this instance to an equivalent double-precision floating-point number using the specified culture-specific formatting information. | |
/// </summary> | |
/// <param name="provider">An <see cref="T:IFormatProvider"></see> interface implementation that supplies culture-specific formatting information.</param> | |
/// <returns> | |
/// A double-precision floating-point number equivalent to the value of this instance. | |
/// </returns> | |
double IConvertible.ToDouble( IFormatProvider provider ) | |
{ | |
return (double)bytes; | |
} | |
/// <summary> | |
/// Converts the value of this instance to an equivalent 16-bit signed integer using the specified culture-specific formatting information. | |
/// </summary> | |
/// <param name="provider">An <see cref="T:IFormatProvider"></see> interface implementation that supplies culture-specific formatting information.</param> | |
/// <returns> | |
/// An 16-bit signed integer equivalent to the value of this instance. | |
/// </returns> | |
short IConvertible.ToInt16( IFormatProvider provider ) | |
{ | |
return (short)bytes; | |
} | |
/// <summary> | |
/// Converts the value of this instance to an equivalent 32-bit signed integer using the specified culture-specific formatting information. | |
/// </summary> | |
/// <param name="provider">An <see cref="T:IFormatProvider"></see> interface implementation that supplies culture-specific formatting information.</param> | |
/// <returns> | |
/// An 32-bit signed integer equivalent to the value of this instance. | |
/// </returns> | |
int IConvertible.ToInt32( IFormatProvider provider ) | |
{ | |
return (int)bytes; | |
} | |
/// <summary> | |
/// Converts the value of this instance to an equivalent 64-bit signed integer using the specified culture-specific formatting information. | |
/// </summary> | |
/// <param name="provider">An <see cref="T:IFormatProvider"></see> interface implementation that supplies culture-specific formatting information.</param> | |
/// <returns> | |
/// An 64-bit signed integer equivalent to the value of this instance. | |
/// </returns> | |
long IConvertible.ToInt64( IFormatProvider provider ) | |
{ | |
return bytes; | |
} | |
/// <summary> | |
/// Converts the value of this instance to an equivalent 8-bit signed integer using the specified culture-specific formatting information. | |
/// </summary> | |
/// <param name="provider">An <see cref="T:IFormatProvider"></see> interface implementation that supplies culture-specific formatting information.</param> | |
/// <returns> | |
/// An 8-bit signed integer equivalent to the value of this instance. | |
/// </returns> | |
sbyte IConvertible.ToSByte( IFormatProvider provider ) | |
{ | |
return (sbyte)bytes; | |
} | |
/// <summary> | |
/// Converts the value of this instance to an equivalent single-precision floating-point number using the specified culture-specific formatting information. | |
/// </summary> | |
/// <param name="provider">An <see cref="T:IFormatProvider"></see> interface implementation that supplies culture-specific formatting information.</param> | |
/// <returns> | |
/// A single-precision floating-point number equivalent to the value of this instance. | |
/// </returns> | |
float IConvertible.ToSingle( IFormatProvider provider ) | |
{ | |
return (float)bytes; | |
} | |
/// <summary> | |
/// Converts the value of this instance to an equivalent <see cref="T:String"></see> using the specified culture-specific formatting information. | |
/// </summary> | |
/// <param name="provider">An <see cref="T:IFormatProvider"></see> interface implementation that supplies culture-specific formatting information.</param> | |
/// <returns> | |
/// A <see cref="T:String"></see> instance equivalent to the value of this instance. | |
/// </returns> | |
string IConvertible.ToString( IFormatProvider provider ) | |
{ | |
return ToString( "A", provider ); | |
} | |
/// <summary> | |
/// Converts the value of this instance to an <see cref="T:Object"></see> of the specified <see cref="T:Type"></see> that has an equivalent value, using the specified culture-specific formatting information. | |
/// </summary> | |
/// <param name="conversionType">The <see cref="T:Type"></see> to which the value of this instance is converted.</param> | |
/// <param name="provider">An <see cref="T:IFormatProvider"></see> interface implementation that supplies culture-specific formatting information.</param> | |
/// <returns> | |
/// An <see cref="T:Object"></see> instance of type conversionType whose value is equivalent to the value of this instance. | |
/// </returns> | |
object IConvertible.ToType( Type conversionType, IFormatProvider provider ) | |
{ | |
IConvertible convertible = this; | |
if ( conversionType == typeof( string ) ) { | |
return convertible.ToString( provider ); | |
} | |
if ( conversionType == typeof( DataSize ) ) { | |
return this; | |
} | |
if ( conversionType == typeof( uint ) ) { | |
return convertible.ToUInt32( provider ); | |
} | |
if ( conversionType == typeof( int ) ) { | |
return convertible.ToInt32( provider ); | |
} | |
if ( conversionType == typeof( ulong ) ) { | |
return convertible.ToUInt64( provider ); | |
} | |
if ( conversionType == typeof( long ) ) { | |
return convertible.ToInt64( provider ); | |
} | |
if ( conversionType == typeof( float ) ) { | |
return convertible.ToSingle( provider ); | |
} | |
if ( conversionType == typeof( double ) ) { | |
return convertible.ToDouble( provider ); | |
} | |
if ( conversionType == typeof( decimal ) ) { | |
return convertible.ToDecimal( provider ); | |
} | |
if ( conversionType == typeof( byte ) ) { | |
return convertible.ToByte( provider ); | |
} | |
if ( conversionType == typeof( sbyte ) ) { | |
return convertible.ToSByte( provider ); | |
} | |
if ( conversionType == typeof( ushort ) ) { | |
return convertible.ToUInt16( provider ); | |
} | |
if ( conversionType == typeof( short ) ) { | |
return convertible.ToInt16( provider ); | |
} | |
if ( conversionType == typeof( bool ) ) { | |
return convertible.ToBoolean( provider ); | |
} | |
if ( conversionType == typeof( DateTime ) ) { | |
return convertible.ToDateTime( provider ); | |
} | |
if ( conversionType == typeof( char ) ) { | |
return convertible.ToChar( provider ); | |
} | |
throw new InvalidCastException( "Unable to convert DataSize to the requested type." ); | |
} | |
/// <summary> | |
/// Converts the value of this instance to an equivalent 16-bit unsigned integer using the specified culture-specific formatting information. | |
/// </summary> | |
/// <param name="provider">An <see cref="T:IFormatProvider"></see> interface implementation that supplies culture-specific formatting information.</param> | |
/// <returns> | |
/// An 16-bit unsigned integer equivalent to the value of this instance. | |
/// </returns> | |
ushort IConvertible.ToUInt16( IFormatProvider provider ) | |
{ | |
return (ushort)bytes; | |
} | |
/// <summary> | |
/// Converts the value of this instance to an equivalent 32-bit unsigned integer using the specified culture-specific formatting information. | |
/// </summary> | |
/// <param name="provider">An <see cref="T:IFormatProvider"></see> interface implementation that supplies culture-specific formatting information.</param> | |
/// <returns> | |
/// An 32-bit unsigned integer equivalent to the value of this instance. | |
/// </returns> | |
uint IConvertible.ToUInt32( IFormatProvider provider ) | |
{ | |
return (uint)bytes; | |
} | |
/// <summary> | |
/// Converts the value of this instance to an equivalent 64-bit unsigned integer using the specified culture-specific formatting information. | |
/// </summary> | |
/// <param name="provider">An <see cref="T:IFormatProvider"></see> interface implementation that supplies culture-specific formatting information.</param> | |
/// <returns> | |
/// An 64-bit unsigned integer equivalent to the value of this instance. | |
/// </returns> | |
ulong IConvertible.ToUInt64( IFormatProvider provider ) | |
{ | |
return (ulong)bytes; | |
} | |
#endregion | |
#region IEquatable<DataSize> Members | |
/// <summary> | |
/// Indicates whether the current object is equal to another object of the same type. | |
/// </summary> | |
/// <param name="other">An object to compare with this object.</param> | |
/// <returns> | |
/// true if the current object is equal to the other parameter; otherwise, false. | |
/// </returns> | |
public bool Equals( DataSize other ) | |
{ | |
return bytes == other.bytes; | |
} | |
#endregion | |
#region IXmlSerializable Members | |
/// <summary> | |
/// This method is reserved and should not be used. When implementing the IXmlSerializable interface, you should return null (Nothing in Visual Basic) from this method, and instead, if specifying a custom schema is required, apply the <see cref="T:XmlSchemaProviderAttribute"/> to the class. | |
/// </summary> | |
/// <returns> | |
/// An <see cref="T:System.Xml.Schema.XmlSchema"/> that describes the XML representation of the object that is produced by the <see cref="M:IXmlSerializable.WriteXml"/> method and consumed by the <see cref="M:IXmlSerializable.ReadXml"/> method. | |
/// </returns> | |
System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema( ) | |
{ | |
return null; | |
} | |
/// <summary> | |
/// Generates an object from its XML representation. | |
/// </summary> | |
/// <param name="reader">The <see cref="T:System.Xml.XmlReader"/> stream from which the object is deserialized.</param> | |
void IXmlSerializable.ReadXml( System.Xml.XmlReader reader ) | |
{ | |
this.bytes = reader.ReadElementContentAsLong( ); | |
} | |
void IXmlSerializable.WriteXml( System.Xml.XmlWriter writer ) | |
{ | |
writer.WriteValue( this.bytes ); | |
} | |
#endregion | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment