【.NET】 TimeSpanをValueTupleで表す

こんにちは、Takymです。
最近は、YouTubeで下らない動画を投稿していました。
今回は、TimeSpanValueTupleを実行時に変換する事が可能なプログラムを作成しました。

ソースコード

using System;
namespace 適当な名前空間
{
/// <summary>
///  <see cref="System.TimeSpan"/>と<see cref="System.ValueTuple{T1, T2, T3}"/>または
///  <see cref="System.ValueTuple{T1, T2, T3, T4, T5}"/>を変換する機能を提供します。
/// </summary>
public struct TimeSpanTuple
{
/// <summary>
///  1日あたり何時間かを表します。
/// </summary>
public const int HoursPerDay = 24;
/// <summary>
///  1時間あたり何分かを表します。
/// </summary>
public const int MinsPerHour = 60;
/// <summary>
///  1分あたり何秒かを表します。
/// </summary>
public const int SecondsPerMin = 60;
/// <summary>
///  1秒あたり何ミリ秒かを表します。
/// </summary>
public const int MilisPerSecond = 1000;
private int _hours, _mins, _seconds, _milis;
/// <summary>
///  日を取得または設定します。
/// </summary>
public int Days { get; set; }
/// <summary>
///  時間を取得またけ設定します。この値は自動的に調整されます。
/// </summary>
public int Hours
{
get
{
return _hours;
}
set
{
this.Days += value / HoursPerDay;
_hours = value % HoursPerDay;
}
}
/// <summary>
///  分を取得またけ設定します。この値は自動的に調整されます。
/// </summary>
public int Mins
{
get
{
return _mins;
}
set
{
this.Hours += value / MinsPerHour;
_mins = value % MinsPerHour;
}
}
/// <summary>
///  秒を取得またけ設定します。この値は自動的に調整されます。
/// </summary>
public int Seconds
{
get
{
return _seconds;
}
set
{
this.Mins += value / SecondsPerMin;
_seconds = value % SecondsPerMin;
}
}
/// <summary>
///  ミリ秒を取得またけ設定します。この値は自動的に調整されます。
/// </summary>
public int Milis
{
get
{
return _milis;
}
set
{
this.Seconds += value / MilisPerSecond;
_milis = value % MilisPerSecond;
}
}
/// <summary>
///  日付、時間、分、秒、ミリ秒を設定して、
///  型'<see cref="適当な名前空間.TimeSpanTuple"/>'の新しいインスタンスを生成します。
/// </summary>
/// <param name="days">日付です。</param>
/// <param name="hours">時間です。</param>
/// <param name="mins">分です。</param>
/// <param name="seconds">秒です。</param>
/// <param name="milis">ミリ秒です。</param>
public TimeSpanTuple(int days, int hours, int mins, int seconds, int milis)
{
_hours = _mins = _seconds = _milis = 0;
this.Days = days;
this.Hours = hours;
this.Mins = mins;
this.Seconds = seconds;
this.Mins = milis;
}
/// <summary>
///  このオブジェクトと指定されたオブジェクトが等しいかどうかを比較します。
/// </summary>
/// <param name="obj">比較対象のオブジェクトです。</param>
/// <returns>比較結果です。等しい場合は<see langword="true"/>、それ以外は<see langword="false"/>です。</returns>
public override bool Equals(object obj)
{
var time = obj as TimeSpanTuple?;
if (time != null) {
return this.Days == time.Value.Days &&
_hours == time.Value._hours &&
_mins == time.Value._mins &&
_milis == time.Value._milis;
}
return false;
}
/// <summary>
///  このオブジェクトのハッシュ値を取得します。
/// </summary>
/// <returns>このオブジェクトのハッシュ値です。</returns>
public override int GetHashCode()
{
return this.Days ^ _hours ^ _mins ^ _seconds ^ _milis;
}
/// <summary>
///  このオブジェクトを判読可能な文字列に変換します。
/// </summary>
/// <returns>日時を表す文字列です。</returns>
public override string ToString()
{
return $"{this.Days:D5}/{_hours:D2}:{_mins:D2}:{_seconds:D2}.{_milis:D3}";
}
/// <summary>
///  このオブジェクトを5つの整数に分解します。
/// </summary>
/// <param name="days">日付です。</param>
/// <param name="hours">時間です。</param>
/// <param name="mins">分です。</param>
/// <param name="seconds">秒です。</param>
/// <param name="milis">ミリ秒です。</param>
public void Deconstruct(out int days, out int hours, out int mins, out int seconds, out int milis)
{
days = this.Days;
hours = _hours;
mins = _mins;
seconds = _seconds;
milis = _milis;
}
/// <summary>
///  このオブジェクトを3つの整数に分解します。
/// </summary>
/// <param name="hours">時間です。</param>
/// <param name="mins">分です。</param>
/// <param name="seconds">秒です。</param>
public void Deconstruct(out int hours, out int mins, out int seconds)
{
hours = _hours;
mins = _mins;
seconds = _seconds;
}
/// <summary>
///  左辺と右辺の値が等しいかどうかを判定します。
/// </summary>
/// <param name="left">左辺です。</param>
/// <param name="right">右辺です。</param>
/// <returns>等しい場合は<see langword="true"/>です。</returns>
public static bool operator ==(TimeSpanTuple left, TimeSpanTuple right)
{
return left.Equals(right);
}
/// <summary>
///  左辺と右辺の値が等しくないかどうかを判定します。
/// </summary>
/// <param name="left">左辺です。</param>
/// <param name="right">右辺です。</param>
/// <returns>等しい場合は<see langword="false"/>です。</returns>
public static bool operator !=(TimeSpanTuple left, TimeSpanTuple right)
{
return left.Equals(right);
}
/// <summary>
///  左辺が右辺の値以下か判定します。
/// </summary>
/// <param name="left">左辺です。</param>
/// <param name="right">右辺です。</param>
/// <returns>小さいまたは等しい場合は<see langword="true"/>です。</returns>
public static bool operator <=(TimeSpanTuple left, TimeSpanTuple right)
{
return ((TimeSpan)(left)) <= ((TimeSpan)(right));
}
/// <summary>
///  左辺が右辺の値以上か判定します。
/// </summary>
/// <param name="left">左辺です。</param>
/// <param name="right">右辺です。</param>
/// <returns>大きいまたは等しい場合は<see langword="true"/>です。</returns>
public static bool operator >=(TimeSpanTuple left, TimeSpanTuple right)
{
return ((TimeSpan)(left)) >= ((TimeSpan)(right));
}
/// <summary>
///  左辺が右辺の値より小さいか判定します。
/// </summary>
/// <param name="left">左辺です。</param>
/// <param name="right">右辺です。</param>
/// <returns>小さい場合は<see langword="true"/>です。</returns>
public static bool operator <(TimeSpanTuple left, TimeSpanTuple right)
{
return ((TimeSpan)(left)) < ((TimeSpan)(right));
}
/// <summary>
///  左辺が右辺の値より大きいか判定します。
/// </summary>
/// <param name="left">左辺です。</param>
/// <param name="right">右辺です。</param>
/// <returns>大きい場合は<see langword="true"/>です。</returns>
public static bool operator >(TimeSpanTuple left, TimeSpanTuple right)
{
return ((TimeSpan)(left)) > ((TimeSpan)(right));
}
/// <summary>
///  二つの時間間隔を加算します。
/// </summary>
/// <param name="left">左辺です。</param>
/// <param name="right">右辺です。</param>
/// <returns>加算された値です。</returns>
public static TimeSpanTuple operator +(TimeSpanTuple left, TimeSpanTuple right)
{
return ((TimeSpan)(left)) + ((TimeSpan)(right));
}
/// <summary>
///  二つの時間間隔を減算します。
/// </summary>
/// <param name="left">左辺です。</param>
/// <param name="right">右辺です。</param>
/// <returns>減算された値です。</returns>
public static TimeSpanTuple operator -(TimeSpanTuple left, TimeSpanTuple right)
{
return ((TimeSpan)(left)) - ((TimeSpan)(right));
}
/// <summary>
///  指定された時間間隔の符号を正にします。
/// </summary>
/// <param name="obj">対象のオブジェクトです。</param>
/// <returns>正にされた値です。</returns>
public static TimeSpanTuple operator +(TimeSpanTuple obj)
{
return +((TimeSpan)(obj));
}
/// <summary>
///  指定された時間間隔の符号を負にします。
/// </summary>
/// <param name="obj">対象のオブジェクトです。</param>
/// <returns>負にされた値です。</returns>
public static TimeSpanTuple operator -(TimeSpanTuple obj)
{
return -((TimeSpan)(obj));
}
/// <summary>
///  時間間隔をタプルに変換します。
/// </summary>
/// <param name="obj">対象のオブジェクトです。</param>
public static implicit operator (int, int, int, int, int) (TimeSpanTuple obj)
{
return (obj.Days, obj._hours, obj._mins, obj._seconds, obj._milis);
}
/// <summary>
///  タプルを時間間隔に変換します。
/// </summary>
/// <param name="obj">対象のオブジェクトです。</param>
public static implicit operator TimeSpanTuple((int, int, int, int, int) obj)
{
TimeSpanTuple result = new TimeSpanTuple();
result.Days = obj.Item1;
result.Hours = obj.Item2;
result.Mins = obj.Item3;
result.Seconds = obj.Item4;
result.Milis = obj.Item5;
return result;
}
/// <summary>
///  時間間隔をタプルに変換します。
/// </summary>
/// <param name="obj">対象のオブジェクトです。</param>
public static implicit operator (int, int, int) (TimeSpanTuple obj)
{
return (obj._hours, obj._mins, obj._seconds);
}
/// <summary>
///  タプルを時間間隔に変換します。
/// </summary>
/// <param name="obj">対象のオブジェクトです。</param>
public static implicit operator TimeSpanTuple((int, int, int) obj)
{
TimeSpanTuple result = new TimeSpanTuple();
result.Hours = obj.Item1;
result.Mins = obj.Item2;
result.Seconds = obj.Item3;
return result;
}
/// <summary>
///  <see cref="適当な名前空間.TimeSpanTuple"/>を<see cref="System.TimeSpan"/>に変換します。
/// </summary>
/// <param name="obj">対象のオブジェクトです。</param>
public static implicit operator TimeSpan(TimeSpanTuple obj)
{
return new TimeSpan(obj.Days, obj._hours, obj._mins, obj._seconds, obj._milis);
}
/// <summary>
///  <see cref="System.TimeSpan"/>を<see cref="適当な名前空間.TimeSpanTuple"/>に変換します。
/// </summary>
/// <param name="obj">対象のオブジェクトです。</param>
public static implicit operator TimeSpanTuple(TimeSpan obj)
{
TimeSpanTuple result = new TimeSpanTuple();
result.Days = obj.Days;
result.Hours = obj.Hours;
result.Mins = obj.Minutes;
result.Seconds = obj.Seconds;
result.Milis = obj.Milliseconds;
return result;
}
}
}

説明

まず、名前空間ですが、簡単にプロジェクトに取り込める様に「適当な名前空間」にしておきました。
各プロパティで設定されている値が上限値を超えている場合は、その値を調節するようにしました。
ただし今回は下限値については考慮していません。
このクラス内で、値を設定する場合はこれらのプロパティを呼び出しています。
Equals、GetHashCode、ToString等の関数をオーバーライドし、値の出力や比較等をできるようにしました。
Deconstructを実装しこのクラスでも分解できるようにしておきましたが、
ValueTupleに変換する事が可能なのであまり意味はないかもしれません。
演算子は比較演算子の==、!=、=、と算術演算子の+、-と単項演算子の+、-を実装していますが、
殆どはTimeSpanを呼び出しているだけです。
また、変換演算子はimplictを使用して暗黙的に変換できるようにしました。(※TimeSpanとValueTupleは直接変換できません。)

後書き

感想・意見・質問・誤字・脱字等はこの記事のコメント欄にお願いします。
最後まで読んでくださってありがとうございました。

コメントを残す

WordPress.com で次のようなサイトをデザイン
始めてみよう