2011-12-02 38 views
12

Tôi đang viết phương thức chấp nhận năm làm tham số. I E. số có bốn chữ số bằng hoặc nhỏ hơn năm hiện tại. Lịch là Gregorian chỉ (cho bây giờ .. không chắc chắn về tương lai) và tôi chắc chắn sẽ không cần bất cứ điều gì BC.Loại thông số cho năm

Tôi đang sử dụng loại dữ liệu nào? giải pháp hiển nhiên sẽ được sử dụng DateTime hoặc Int32:

public void MyFunction(DateTime date) 
{ 
    // year to work with: date.Year; 
    // date.Month, date.Day, etc. is irrelevant and will always be 
} 

hoặc

public void MyFunction(Int year) 
{ 
    if (year > 9999 || otherValidations == false) 
    { 
     //throw new Exception... 
    } 

    // year to work with: new DateTime(year, 1, 1); 
} 

Bất kỳ lựa chọn thay thế khác ngoài văn bản của riêng tôi kiểu dữ liệu tùy chỉnh Năm?

+2

Phụ thuộc vào những gì bạn đang làm với nó sau đó và những gì được gọi nó. Bạn có phơi bày điều này với tư cách giao diện không? Nguồn gốc đến từ đâu? Bạn có thể chỉ cần một Int16 nếu tất cả những gì bạn đang làm là so sánh nó. –

+4

Đừng phát minh ra một bánh xe, tôi sẽ đề nghị Giữ nó đơn giản và sử dụng được xây dựng trong 'int' kiểu dữ liệu – sll

+3

Năm * trong lịch *? Gregorian? Hebrew? Hijri? Những người dùng khác nhau sử dụng các hệ thống lịch khác nhau ở các vị trí khác nhau; nếu bạn muốn phần mềm của bạn có thể sử dụng được bởi tất cả chúng, bạn có thể có một số nghiên cứu để làm. –

Trả lời

26

An int sẽ hoạt động tốt trong hầu hết các trường hợp.

Đó là những gì DateTime.Year là và đó là những gì các nhà xây dựng DateTime đưa vào, vì vậy trừ khi bạn có lý do cụ thể để cần một loại dữ liệu khác, một số nguyên có lẽ là điều dễ nhất để làm việc.

+4

Tôi thích điều này vì đây là phương pháp đơn giản nhất (đơn giản hơn việc tạo một đối tượng đặc biệt để giữ Năm) và nó không cho người dùng của bạn cơ hội để nghĩ rằng các thành phần khác của DateTime có liên quan. – deepee1

+1

+1 để sử dụng cùng loại với BCL. – DaveShaw

3

Bạn có thể bọc nó vào một số struct bất biến nhưng về cơ bản nó một số int có một số hạn chế.

1

Tôi muốn nói: truy cập DateTime vì bạn đã có các hoạt động được xác định mà bạn có thể cần. Tại sao tái tạo lại bánh xe?

4

Có thể là int. Việc chấp nhận một đối tượng DateTime toàn bộ sẽ gây nhầm lẫn, vì phương thức của bạn chỉ cần một năm. Từ đó, int là sự lựa chọn hợp lý vì nó là kiểu thuộc tính DateTime.Year.

0

Tạo kiểu dữ liệu tùy chỉnh Year. Nó nhanh hơn so với yêu cầu ở đây trên SO :-) Bạn có thể khai báo nó như là một struct để nhận được hành vi tương tự như khi sử dụng int nhưng thêm ràng buộc rất cụ thể của bạn trong logic của loại.

4

Điều này phụ thuộc rất nhiều vào những gì bạn định làm trong năm. Nếu bạn dự định truyền nó xung quanh rất nhiều, việc tạo tùy chỉnh struct đóng gói một int của bạn có thể là một ý tưởng hay, bởi vì bạn sẽ không cần phải xác thực cùng một số nhiều lần. Nếu không, một đồng bằng cũ int sẽ hoạt động tốt.

1

Năm là int. nhưng nếu bạn có thể thay đổi nó thành tài sản, bạn có thể thêm một số xác nhận trong thiết lập, Ngoài ra nếu chỉ cần nhập vào một số chức năng bạn có thể thêm chức năng mới để xác nhận nó.

int year; 
public int Year 
{ 
    get 
    { 
     if (year > 9999) 
      throw ... 
     // check other constrains ... 
     return year; 
    } 
    set 
    { 
     if (value > 9999) 
     throw ... 
     // check other constrains ... 

     year = value; 
    } 
} 

Là một chức năng:

int GetYear(int year) 
{ 
    do validation and possibly throw an exception 
    return year; 
} 

nhưng nếu bạn sử dụng nó chỉ trong một chức năng không cần làm bất kỳ trong số họ, làm kiểm chứng thực của bạn trong chức năng có trách nhiệm.

1

Tôi sẽ sử dụng int trừ khi bạn có kế hoạch phải đối phó với BC hoặc không phải năm Gregory (với chuyển đổi giữa chúng). Trong trường hợp BC, bạn có thể muốn cấu trúc Year cho mục đích hiển thị thông qua ToString. Trong trường hợp phi Gregorian, mọi thứ trở nên phức tạp hơn.

1

Mặc dù có thể sử dụng một int, nhưng cách tốt nhất là thực hiện một cấu trúc đặc biệt, vì nó thể hiện ý định của bạn tốt hơn:

public struct Year : IEquatable<Year>, IEquatable<DateTime>, IEquatable<int> 
{ 
    /// <summary> 
    /// 
    /// </summary> 
    /// <param name="year"></param> 
    /// <exception cref="ArgumentOutOfRangeException"> 
    ///  When <see cref="year"/> is not within the range from <value>1</value> to <value>9999</value>. 
    /// </exception> 
    public Year(int year) 
    { 
     // same limits as DateTime 
     // be careful when changing this values, because it might break 
     // conversion from and to DateTime 
     var min = 1; 
     var max = 9999; 

     if (year < min || year > max) 
     { 
      var message = string.Format("Year must be between {0} and {1}.", min, max); 
      throw new ArgumentOutOfRangeException("year", year, message); 
     } 

     _value = year; 
    } 

    private readonly int _value; 

    public bool Equals(Year other) 
    { 
     return _value == other._value; 
    } 

    public bool Equals(DateTime other) 
    { 
     return _value == other.Year; 
    } 

    public bool Equals(int other) 
    { 
     return _value == other; 
    } 

    public override bool Equals(object obj) 
    { 
     if (ReferenceEquals(null, obj)) 
     { 
      return false; 
     } 

     if (obj is Year) return Equals((Year) obj); 
     if (obj is int) return Equals((int)obj); 
     if (obj is DateTime) return Equals((DateTime) obj); 
     return false; 
    } 

    public static Year MinValue 
    { 
     get 
     { 
      return new Year(DateTime.MinValue.Year); 
     } 
    } 

    public static Year MaxValue 
    { 
     get 
     { 
      return new Year(DateTime.MaxValue.Year); 
     } 
    } 

    public override int GetHashCode() 
    { 
     return _value; 
    } 

    public static bool operator ==(Year left, Year right) 
    { 
     return left.Equals(right); 
    } 

    public static bool operator !=(Year left, Year right) 
    { 
     return !left.Equals(right); 
    } 

    public override string ToString() 
    { 
     return _value.ToString(); 
    } 

    public string ToString(IFormatProvider formatProvider) 
    { 
     return _value.ToString(formatProvider); 
    } 

    public string ToString(string format) 
    { 
     return _value.ToString(format); 
    } 

    public string ToString(string format, IFormatProvider formatProvider) 
    { 
     return _value.ToString(format, formatProvider); 
    } 

    public DateTime ToDateTime() 
    { 
     return new DateTime(_value, 1, 1); 
    } 

    public int ToInt() 
    { 
     return _value; 
    } 

    public static implicit operator DateTime(Year year) 
    { 
     return new DateTime(year._value, 1, 1); 
    } 

    public static explicit operator Year(DateTime dateTime) 
    { 
     return new Year(dateTime.Year); 
    } 

    public static explicit operator int(Year year) 
    { 
     return year._value; 
    } 

    /// <summary> 
    /// 
    /// </summary> 
    /// <param name="year"></param> 
    /// <returns></returns> 
    /// <exception cref="ArgumentOutOfRangeException"> 
    ///  When <see cref="year"/> is not within the range from <value>1</value> to <value>9999</value>. 
    /// </exception> 
    public static explicit operator Year(int year) 
    { 
     return new Year(year); 
    } 
} 
Các vấn đề liên quan