Custom ShortDate type (struct: IComparable)






3.24/5 (12 votes)
Feb 14, 2005
2 min read

62762

88
A struct example
Introduction
Here is a custom C# .NET Date
type (struct
) that will help you deal with conversions to and from string
s. The struct
implements the IComparable
interface and overrides the ToString
, Equals
and GetHashCode()
functions.
Background
Defining a struct
is almost similar to that of defining a class
:
[attributes] [modifiers] struct <structName> [: interfaces]
{
[struct-body]
}[;]
Like a class
, a struct
can contain other types and is sometimes referred to as a lightweight version of a class
because internally a struct
is a value type. Creating a struct
instance will not cause garbage collection (unless the constructor directly or indirectly creates a reference type instance) whereas creating a reference type instance can cause garbage collection. Another thing about a struct
is that it always has a built-in public
default constructor and no destructor.
How is a struct
different from a class
:
- a
struct
is implicitlysealed
, aclass
isn't - a
struct
can't beabstract
, aclass
can - a
struct
can't call: base()
in its constructor whereas aclass
with no explicitbase
class can - a
struct
can't extend anotherclass
, aclass
can - a
struct
can't declareprotected
members (e.g. fields, nested types) aclass
can - a
struct
can't declareabstract
function members, anabstract class
can - a
struct
can't declarevirtual
function members, aclass
can - a
struct
can't declaresealed
function members, aclass
can - a
struct
can't declareoverride
function members, aclass
can. The only exception to this rule is that astruct
can override thevirtual
methods ofSystem.Object
, viz,Equals()
, andGetHashCode()
, andToString()
(more info on StructsVsClasses)
Struct Code
The Date
struct
looks like this:
using System;
using System.Text.RegularExpressions;
[Serializable]
public struct Date : IComparable
{
//private members
//public members
//constructor
//functions
//IComparable & overridden implementation
}
I want to build a ShortDate
struct
with three fields:
private UInt16 _day;
private UInt16 _month;
private UInt16 _year;
Next, I make those fields public
, so now my struct
has three properties:
public UInt16 Day
{
get { return _day; }
set
{
if (value > 31)
{
throw new ArgumentException("Day out of range[31]");
}
else
{
_day = value;
}
}
}
public UInt16 Month
{
get { return _month; }
set
{
if (value > 12)
{
throw new ArgumentException("Month out of range[12]");
}
else
{
_month = value;
}
}
}
public UInt16 Year
{
get { return _year; }
set
{
if (value.ToString().Length > 4)
{
throw new ArgumentException("Year out of range.");
}
else
{
_year = value;
}
}
}
Besides the default constructor that makes all the fields equal to zero, I've made another one that will fill the fields with data from the DateTime
parameter:
public Date(DateTime dt)
{
_month = Convert.ToUInt16(dt.Month);
_day = Convert.ToUInt16(dt.Day);
_year = Convert.ToUInt16(dt.Year);
}
IComparable
implementation and overrides of the ToString
, Equals
and GetHashCode()
functions:
public int CompareTo(object obj)
{
Date dt = (Date) obj;
UInt16 i = 0;
if (dt._day == _day)
{
i += 100;
}
if (dt._month == _month)
{
i += 010;
}
if (dt._year == _year)
{
i += 001;
}
return i;
}
public override bool Equals(object obj)
{
if (obj == null || ! (obj is Date))
return false;
try
{
Date other = (Date)obj;
return this._day == other._day
&& this._month == other._month
&& this._year == other._year;
}
catch
{
return false;
}
}
public override int GetHashCode()
{
return (_day ^ _month ^ _year);
}
public override string ToString()
{
return (_day.ToString() + "/" + _month.ToString() + "/" + _year.ToString());
}
public string ToString(string separator)
{
string s1="", s2="";
if(_day.ToString().Length == 1 )
{
s1="0";
}
if( _month.ToString().Length == 1 )
{
s2="0";
}
return (s1+_day.ToString()+separator+s2+_month.ToString()+separator+_year);
}
public static bool operator >(Date d1,Date d2)
{
if( d1.ToDateTime() > d2.ToDateTime() )
{
return true;
}
return false;
}
public static bool operator <(Date d1,Date d2)
{
if( d1.ToDateTime() < d2.ToDateTime() )
{
return true;
}
return false;
}
And finally some useful functions to help us manage this Date
type:
public bool IsDateTime(string dt)
{
Regex rgx = new
Regex(@"(?<Day>\d{1,2})/(?<Month>\d{1,2})/(?<Year>(?:\d{4}|\d{2}))");
if (rgx.IsMatch(dt))
{
return true;
}
else
{
return false;
}
}
public DateTime StringToDate(string dt)
{
if (IsDateTime(dt))
{
_day = Convert.ToUInt16(dt.Split('/')[0]);
_month = Convert.ToUInt16(dt.Split('/')[1]);
_year = Convert.ToUInt16(dt.Split('/')[2]);
}
else
{
throw new ArgumentException("The string can't be converted to a date");
}
return new DateTime(Year, Month, Day);
}
public DateTime StringToDate(string dt, char separator)
{
try
{
_day = Convert.ToUInt16(dt.Split(separator)[0]);
_month = Convert.ToUInt16(dt.Split(separator)[1]);
_year = Convert.ToUInt16(dt.Split(separator)[2]);
return new DateTime(Year, Month, Day);
}
catch (Exception)
{
throw new InvalidCastException("The input string is not a date format");
}
}
public DateTime ToDateTime()
{
return new DateTime(Year, Month, Day);
}
public static DateTime ToDateTime(Date dt)
{
return new DateTime(dt.Year, dt.Month, dt.Day);
}
Using the Code
You can now include the struct
into a project and try it out, here are some examples:
private void Page_Load(object sender, System.EventArgs e)
{
//default constructor
Date d1 = new Date();
Response.Write("Luna: "+d1.Month+" Zi: "+d1.Day+" An: "+d1.Year);
//defined constructor
Date d2 = new Date(DateTime.Now);
Response.Write(d2.ToString());
//StringToDate will fill the fields
Date d3 = new Date();
Response.Write(d3.StringToDate("01/02/05"));
Response.Write(d1.ToString()+" -d1- "+ d1.GetHashCode());
Response.Write(d2.ToString()+" -d2- "+ d2.GetHashCode());
Response.Write(d3.ToString()+" -d3- "+ d3.GetHashCode());
Date d4 = new Date();
d4.StringToDate("01/02/05");
Date d5 = new Date();
d5.Day = 1;
d5.Month = 5;
d5.Year = 05;
Response.Write(d4.ToString()+" Equals "+d5.ToString()+
"? "+d4.Equals(d5));
Response.Write(d4.ToString()+" CompareTo "+d5.ToString()+
"? "+d4.CompareTo(d5));
}
History
- Version 2.0
License
This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.
A list of licenses authors might use can be found here.