65.9K
CodeProject 正在变化。 阅读更多。
Home

自定义 ShortDate 类型 (结构: IComparable)

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.24/5 (12投票s)

2005年2月14日

2分钟阅读

viewsIcon

63211

downloadIcon

101

一个 struct 例子

引言

这是一个自定义的 C# .NET Date 类型 (struct),可以帮助你处理与 string 之间的转换。 该 struct 实现了 IComparable 接口,并重写了 ToString, EqualsGetHashCode() 函数。

背景

定义一个 struct 几乎和定义一个 class 类似

[attributes] [modifiers] struct <structName> [: interfaces]
{
    [struct-body]
}[;]

class 一样, struct 可以包含其他类型,有时被称为 class 的轻量级版本,因为在内部 struct 是一个值类型。 创建一个 struct 实例不会导致垃圾回收 (除非构造函数直接或间接地创建一个引用类型实例),而创建一个引用类型实例可能会导致垃圾回收。 关于 struct 的另一件事是它始终有一个内置的 public 默认构造函数,并且没有析构函数。

structclass 有什么不同

  • struct 是隐式 sealed 的,而 class 不是
  • struct 不能是 abstract 的,而 class 可以
  • struct 无法在其构造函数中调用 : base(),而没有显式 base 类的 class 可以
  • struct 无法扩展另一个 class,而 class 可以
  • struct 无法声明 protected 成员 (例如字段,嵌套类型),而 class 可以
  • struct 无法声明 abstract 函数成员,而 abstract class 可以
  • struct 无法声明 virtual 函数成员,而 class 可以
  • struct 无法声明 sealed 函数成员,而 class 可以
  • struct 无法声明 override 函数成员,而 class 可以。 此规则的唯一例外是 struct 可以覆盖 System.Objectvirtual 方法,即 Equals(), 和 GetHashCode(), 以及 ToString() (更多信息请访问 StructsVsClasses)

Struct 代码

Date struct 看起来像这样

using System;
using System.Text.RegularExpressions;

[Serializable]
public struct Date : IComparable
{
    //private members
    
    //public members
    
    //constructor
    
    //functions
    
    //IComparable & overridden implementation
}

我想构建一个包含三个字段的 ShortDate struct

private UInt16 _day;
private UInt16 _month;
private UInt16 _year;

接下来,我将这些字段设置为 public,所以现在我的 struct 有三个属性

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;
        }
    }
}

除了使所有字段都等于零的默认构造函数外,我还创建了另一个构造函数,它将使用来自 DateTime 参数的数据填充这些字段

public Date(DateTime dt)
{
    _month = Convert.ToUInt16(dt.Month);
    _day = Convert.ToUInt16(dt.Day);
    _year = Convert.ToUInt16(dt.Year);
}

IComparable 的实现和 ToString, EqualsGetHashCode() 函数的重写

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;
}

最后是一些有用的函数来帮助我们管理这个 Date 类型

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

您现在可以将此 struct 包含到项目中并尝试一下,这里有一些例子

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));
}

历史

  • 版本 2.0

许可证

本文未附加明确的许可证,但可能在文章文本或下载文件本身中包含使用条款。如有疑问,请通过下面的讨论区联系作者。

作者可能使用的许可证列表可以在此处找到。

© . All rights reserved.