date.IsWithIn(x months).Of(Comparison Date) 之类的 C# 语法是什么?
What is the C# Syntax for something like date.IsWithIn(x months).Of(Comparison Date)?
标题有点古怪,但这就是问题所在。我正在使用 C#。我正在尝试提出几种 DateTime 扩展方法。边想边想,我要用什么语法写出如下代码:
DateTime comparisonDate = DateTime.Now.AddMonths(-3);
if( DateTime.Now.IsWithIn(3).Of(comparisonDate) ) ....
我以前写过扩展方法,但我不确定如何编写这样的东西。 "IsWithIn" 是一种方法...但是 return 是一个表达式,而 "Of" 方法是表达式 class 的扩展方法吗?
编辑 1
还在想这个。我想知道这种方法虽然可读,但是否会使事情复杂化。我的第一次修订只是调整了@Wai Ha Lee 的 DateTimeExtensions class。我将重构它并继续迭代。这尖叫策略模式,但我还没有适应它呢。现在也没有 "Of" 方法,方法名称似乎有意义......至少在今天是这样。一个月后?我不确定。
我还想到了另一种方式来编写这段代码。我想我还在做梦,但事情就是这样:
date.IsWithIn(1).Days().Of(comparisonDate);
date.IsWithIn(1).Months().Of(comparisonDate);
date.IsWithIn(1).Years().Of(comparisonDate);
但除此之外,这是我的修订版本,它只是没有方法名称链接的 DateTime 扩展。
public class Program
{
static void Main(string[] args)
{
DateTime now = DateTime.Now;
DateTime past = new DateTime(2015, 1, 15);
DateTime future = new DateTime(2015, 3, 15);
DateTime comparison = now.AddDays(-2);
int interval = 1;
DateInterval di = DateInterval.Days;
Console.WriteLine(
string.Format("Now, {0}, is with in {1} {2} of {3} is {4}",
now.ToShortDateString(),
interval.ToString(),
di.ToString(),
comparison.ToShortDateString(),
now.IsDateWithinXRangeOfAnotherDate(interval, di, comparison).ToString())
);
Console.ReadLine();
}
}
public enum DateInterval
{
Days,
Months,
Years
}
public static class DateTimeExtensions
{
public static bool IsDateWithinXRangeOfAnotherDate(this DateTime date, int interval, DateInterval dateInterval, DateTime comparisonDate)
{
DateTime _min = comparisonDate;
DateTime _max = comparisonDate;
switch(dateInterval)
{
case DateInterval.Days:
_min = _min.AddDays(-interval);
_max = _max.AddDays(interval);
Console.WriteLine(
string.Format("Min Date is {0} Max Date is {1}",
_min.ToShortDateString(),
_max.ToShortDateString()));
break;
case DateInterval.Months:
_min = _min.AddMonths(-interval);
_max = _max.AddMonths(interval);
Console.WriteLine(
string.Format("Min Date is {0} Max Date is {1}",
_min.ToShortDateString(),
_max.ToShortDateString()));
break;
case DateInterval.Years:
_min = _min.AddYears(-interval);
_max = _max.AddYears(interval);
Console.WriteLine(
string.Format("Min Date is {0} Max Date is {1}",
_min.ToShortDateString(),
_max.ToShortDateString()));
break;
}
return _min <= date && date <= _max;
}
}
编辑 2
修改中:
date.IsWithIn(1).Days().Of(comparisonDate);
date.IsWithIn(1).Months().Of(comparisonDate);
date.IsWithIn(1).Years().Of(comparisonDate);
到
date.IsWithIn(1.Days()).Of(comparisonDate);
date.IsWithIn(1.Months()).Of(comparisonDate);
date.IsWithIn(1.Years()).Of(comparisonDate);
稍微查看 FluentTime 后,我注意到作者使用了几种方法和 class我什至不知道存在的方法。其一,他使用了 TimeSpan.FromDays 方法。他可能重载了 + 符号,因为在代码的另一处,他只是将时间跨度添加到日期。考虑到 TimeSpans 的工作方式,我可能只能实现 1.Days() 部分……我认为这就是我真正需要的。
我会继续尝试所有这些,直到我弄明白为止。我可以只使用 FluentTime 库,但它对我需要它的用途来说太过分了,因为该库也处理时间。我对日期范围比较非常感兴趣。 After()、Before()、IsBetween()、IsWithIn 等方法。我已经实施了前 3 个。这个问题的重点是回答最后一个问题。
编辑 3 - 已解决!
这个问题更像是一个代码练习,而不是实用性。最终,Jon Skeet 关于必须创建自定义类型的观点是正确的。解决方案分解为以下摘要:
自定义 class:已创建 FluentDateTime
3 种 int 扩展方法 - 日、月、年。这些每个 return 一个 FluentDateTime class。
1 DateTime 扩展方法 - IsWithIn 采用 FluentDateTime 参数
我想强调的是,这是非常小的成功......但是,无论如何,这是代码。
public class FluentDateTime
{
public enum DateInterval
{
Days,
Months,
Years
}
private DateTime _lowDate;
private DateTime _highDate;
public DateTime BaseDate { get; set; }
public DateInterval Interval { get; set; }
public int Increment { get; set; }
public bool Of(DateTime dt)
{
_lowDate = dt;
_highDate = dt;
if(this.Interval == DateInterval.Days)
{
_lowDate = _lowDate.AddDays(-this.Increment);
_highDate = _highDate.AddDays(this.Increment);
}
else if (this.Interval == DateInterval.Months)
{
_lowDate = _lowDate.AddMonths(-this.Increment);
_highDate = _highDate.AddMonths(this.Increment);
}
else
{
_lowDate = _lowDate.AddYears(-this.Increment);
_highDate = _highDate.AddYears(this.Increment);
}
Console.WriteLine(
string.Format("{0} <= {1} <= {2}", _lowDate.ToShortDateString(), BaseDate.ToShortDateString(), _highDate.ToShortDateString()
));
return (_lowDate < BaseDate && BaseDate < _highDate) || (_lowDate.Equals(BaseDate) || _highDate.Equals(BaseDate) );
}
}
// 日期时间扩展
public static FluentDateTime IsWithIn(this DateTime date, FluentDateTime fdtParams)
{
fdtParams.BaseDate = date;
return fdtParams;
}
//INT 扩展
public static FluentDateTime Days(this int inc)
{
FluentDateTime fdt = new FluentDateTime();
fdt.Interval = FluentDateTime.DateInterval.Days;
fdt.Increment = inc;
return fdt;
}
public static FluentDateTime Months(this int inc)
{
FluentDateTime fdt = new FluentDateTime();
fdt.Interval = FluentDateTime.DateInterval.Months;
fdt.Increment = inc;
return fdt;
}
public static FluentDateTime Years(this int inc)
{
FluentDateTime fdt = new FluentDateTime();
fdt.Interval = FluentDateTime.DateInterval.Years;
fdt.Increment = inc;
return fdt;
}
//测试程序
DateTime testDate1 = new DateTime(2015, 3, 3);
DateTime testDate2 = new DateTime(2015, 3, 4);
Console.WriteLine(
string.Format("{0} is within 5 days of {1}? {2} (should be true)",
testDate1.ToShortDateString(), testDate2.ToShortDateString(), testDate1.IsWithIn(5.Days()).Of(testDate2)
));
testDate1 = new DateTime(2015, 3, 1);
testDate2 = new DateTime(2015, 3, 7);
Console.WriteLine(
string.Format("{0} is within 3 days of {1}? {2} (should be false)",
testDate1.ToShortDateString(), testDate2.ToShortDateString(), testDate1.IsWithIn(3.Days()).Of(testDate2)
));
testDate1 = new DateTime(2015, 3, 3);
testDate2 = new DateTime(2015, 4, 1);
Console.WriteLine(
string.Format("{0} is within 1 month of {1}? {2} (should be true)",
testDate1.ToShortDateString(), testDate2.ToShortDateString(), testDate1.IsWithIn(1.Months()).Of(testDate2)
));
testDate1 = new DateTime(2015, 3, 3);
testDate2 = new DateTime(2015, 6, 1);
Console.WriteLine(
string.Format("{0} is within 2 month of {1}? {2} (should be false)",
testDate1.ToShortDateString(), testDate2.ToShortDateString(), testDate1.IsWithIn(2.Months()).Of(testDate2)
));
IsWithin
必须 return 表示值范围的某种类型,记住 "centre" 和范围大小。现在 Of
可以是它的扩展方法,或者很容易成为普通实例方法,前提是您要自己编写类型。
请注意,3
并不清楚是 3 天、3 小时还是其他时间。你应该弄清楚你想如何指定它。您可以采用 TimeSpan
而不仅仅是 int
,或者使用单独的 IsWithinDays
、IsWithinHours
等方法。
一些事情:
- 我假设 within
{some time}
of 意味着 {some time}
的任一侧 - 如果它只是指之后,代码就简单多了。保持我的假设意味着 .IsWithin(x).Of
是可交换的,即 a.IsWithin(x).Of(b) == b.IsWithin(x).Of(a)
.
DateTimeRange
采用 Func<DateTime, int, DateTime>
以避免重复代码(尽管如果我假设 a 则没有范围)
- 我不使用 TimeSpan 因为
The largest unit of time that the TimeSpan structure uses to measure duration is a day.
- Without hyperbole, this is the worst thing ever, and I hate myself a little for posting this. I would never write code like this in a professional context. I've only done this to (almost) satisfy @jason's requirements (I renamed
IsWithIn
to IsWithin
).
Usage
public static void Main()
{
var now = DateTime.Now;
var comparisonDate = now.AddMonths(-2);
bool within1Month = now.IsWithin(months: 1).Of(comparisonDate); // false
bool within2Months = now.IsWithin(months: 2).Of(comparisonDate); // true
bool within3Months = now.IsWithin(months: 3).Of(comparisonDate); // true
}
日期时间扩展:
public static class DateTimeExtensions
{
/// <summary>
/// <para>Specify exactly one of milliseconds, seconds, minutes, hours, days, months, or years.</para>
/// <para>Uses the first nonzero argument in the order specified.</para>
/// </summary>
public static DateTimeRange IsWithin(
this DateTime dateTime,
int milliseconds = 0, int seconds = 0, int minutes = 0, int hours = 0,
int days = 0, int months = 0, int years = 0)
{
if ( milliseconds != 0 )
return new DateTimeRange(dateTime, (_dateTime, _value) => _dateTime.AddMilliseconds(_value), milliseconds);
if ( seconds != 0 )
return new DateTimeRange(dateTime, (_dateTime, _value) => _dateTime.AddSeconds(_value), seconds);
if ( minutes != 0 )
return new DateTimeRange(dateTime, (_dateTime, _value) => _dateTime.AddMinutes(_value), minutes);
if ( hours != 0 )
return new DateTimeRange(dateTime, (_dateTime, _value) => _dateTime.AddHours(_value), hours);
if ( days != 0 )
return new DateTimeRange(dateTime, (_dateTime, _value) => _dateTime.AddDays(_value), days);
if ( months != 0 )
return new DateTimeRange(dateTime, (_dateTime, _value) => _dateTime.AddMonths(_value), months);
if ( years != 0 )
return new DateTimeRange(dateTime, (_dateTime, _value) => _dateTime.AddYears(_value), years);
throw new ArgumentException("At least one value must be nonzero");
}
}
日期时间范围:
/// <summary>
/// Represents a range between two DateTime values
/// </summary>
public struct DateTimeRange
{
private DateTime _min;
private DateTime _max;
public DateTime Min { get { return _min; } }
public DateTime Max { get { return _max; } }
/// <summary>
/// Uses generator to get the start and end dates of this range.
/// </summary>
/// <param name="middle">The midpoint of this DateTimeRange</param>
/// <param name="generator">Generates the min and max dates from the midpoint and a parameter</param>
public DateTimeRange(DateTime middle, Func<DateTime, int, DateTime> generator, int value)
{
_min = generator(middle, -value);
_max = generator(middle, +value);
}
public bool Of(DateTime dateTime)
{
return _min <= dateTime && dateTime <= _max;
}
}
我觉得有点惭愧 post 这是@jonskeet 回答的问题的唯一其他答案。
标题有点古怪,但这就是问题所在。我正在使用 C#。我正在尝试提出几种 DateTime 扩展方法。边想边想,我要用什么语法写出如下代码:
DateTime comparisonDate = DateTime.Now.AddMonths(-3);
if( DateTime.Now.IsWithIn(3).Of(comparisonDate) ) ....
我以前写过扩展方法,但我不确定如何编写这样的东西。 "IsWithIn" 是一种方法...但是 return 是一个表达式,而 "Of" 方法是表达式 class 的扩展方法吗?
编辑 1
还在想这个。我想知道这种方法虽然可读,但是否会使事情复杂化。我的第一次修订只是调整了@Wai Ha Lee 的 DateTimeExtensions class。我将重构它并继续迭代。这尖叫策略模式,但我还没有适应它呢。现在也没有 "Of" 方法,方法名称似乎有意义......至少在今天是这样。一个月后?我不确定。
我还想到了另一种方式来编写这段代码。我想我还在做梦,但事情就是这样:
date.IsWithIn(1).Days().Of(comparisonDate);
date.IsWithIn(1).Months().Of(comparisonDate);
date.IsWithIn(1).Years().Of(comparisonDate);
但除此之外,这是我的修订版本,它只是没有方法名称链接的 DateTime 扩展。
public class Program
{
static void Main(string[] args)
{
DateTime now = DateTime.Now;
DateTime past = new DateTime(2015, 1, 15);
DateTime future = new DateTime(2015, 3, 15);
DateTime comparison = now.AddDays(-2);
int interval = 1;
DateInterval di = DateInterval.Days;
Console.WriteLine(
string.Format("Now, {0}, is with in {1} {2} of {3} is {4}",
now.ToShortDateString(),
interval.ToString(),
di.ToString(),
comparison.ToShortDateString(),
now.IsDateWithinXRangeOfAnotherDate(interval, di, comparison).ToString())
);
Console.ReadLine();
}
}
public enum DateInterval
{
Days,
Months,
Years
}
public static class DateTimeExtensions
{
public static bool IsDateWithinXRangeOfAnotherDate(this DateTime date, int interval, DateInterval dateInterval, DateTime comparisonDate)
{
DateTime _min = comparisonDate;
DateTime _max = comparisonDate;
switch(dateInterval)
{
case DateInterval.Days:
_min = _min.AddDays(-interval);
_max = _max.AddDays(interval);
Console.WriteLine(
string.Format("Min Date is {0} Max Date is {1}",
_min.ToShortDateString(),
_max.ToShortDateString()));
break;
case DateInterval.Months:
_min = _min.AddMonths(-interval);
_max = _max.AddMonths(interval);
Console.WriteLine(
string.Format("Min Date is {0} Max Date is {1}",
_min.ToShortDateString(),
_max.ToShortDateString()));
break;
case DateInterval.Years:
_min = _min.AddYears(-interval);
_max = _max.AddYears(interval);
Console.WriteLine(
string.Format("Min Date is {0} Max Date is {1}",
_min.ToShortDateString(),
_max.ToShortDateString()));
break;
}
return _min <= date && date <= _max;
}
}
编辑 2
修改中:
date.IsWithIn(1).Days().Of(comparisonDate);
date.IsWithIn(1).Months().Of(comparisonDate);
date.IsWithIn(1).Years().Of(comparisonDate);
到
date.IsWithIn(1.Days()).Of(comparisonDate);
date.IsWithIn(1.Months()).Of(comparisonDate);
date.IsWithIn(1.Years()).Of(comparisonDate);
稍微查看 FluentTime 后,我注意到作者使用了几种方法和 class我什至不知道存在的方法。其一,他使用了 TimeSpan.FromDays 方法。他可能重载了 + 符号,因为在代码的另一处,他只是将时间跨度添加到日期。考虑到 TimeSpans 的工作方式,我可能只能实现 1.Days() 部分……我认为这就是我真正需要的。
我会继续尝试所有这些,直到我弄明白为止。我可以只使用 FluentTime 库,但它对我需要它的用途来说太过分了,因为该库也处理时间。我对日期范围比较非常感兴趣。 After()、Before()、IsBetween()、IsWithIn 等方法。我已经实施了前 3 个。这个问题的重点是回答最后一个问题。
编辑 3 - 已解决!
这个问题更像是一个代码练习,而不是实用性。最终,Jon Skeet 关于必须创建自定义类型的观点是正确的。解决方案分解为以下摘要:
自定义 class:已创建 FluentDateTime 3 种 int 扩展方法 - 日、月、年。这些每个 return 一个 FluentDateTime class。 1 DateTime 扩展方法 - IsWithIn 采用 FluentDateTime 参数
我想强调的是,这是非常小的成功......但是,无论如何,这是代码。
public class FluentDateTime
{
public enum DateInterval
{
Days,
Months,
Years
}
private DateTime _lowDate;
private DateTime _highDate;
public DateTime BaseDate { get; set; }
public DateInterval Interval { get; set; }
public int Increment { get; set; }
public bool Of(DateTime dt)
{
_lowDate = dt;
_highDate = dt;
if(this.Interval == DateInterval.Days)
{
_lowDate = _lowDate.AddDays(-this.Increment);
_highDate = _highDate.AddDays(this.Increment);
}
else if (this.Interval == DateInterval.Months)
{
_lowDate = _lowDate.AddMonths(-this.Increment);
_highDate = _highDate.AddMonths(this.Increment);
}
else
{
_lowDate = _lowDate.AddYears(-this.Increment);
_highDate = _highDate.AddYears(this.Increment);
}
Console.WriteLine(
string.Format("{0} <= {1} <= {2}", _lowDate.ToShortDateString(), BaseDate.ToShortDateString(), _highDate.ToShortDateString()
));
return (_lowDate < BaseDate && BaseDate < _highDate) || (_lowDate.Equals(BaseDate) || _highDate.Equals(BaseDate) );
}
}
// 日期时间扩展
public static FluentDateTime IsWithIn(this DateTime date, FluentDateTime fdtParams)
{
fdtParams.BaseDate = date;
return fdtParams;
}
//INT 扩展
public static FluentDateTime Days(this int inc)
{
FluentDateTime fdt = new FluentDateTime();
fdt.Interval = FluentDateTime.DateInterval.Days;
fdt.Increment = inc;
return fdt;
}
public static FluentDateTime Months(this int inc)
{
FluentDateTime fdt = new FluentDateTime();
fdt.Interval = FluentDateTime.DateInterval.Months;
fdt.Increment = inc;
return fdt;
}
public static FluentDateTime Years(this int inc)
{
FluentDateTime fdt = new FluentDateTime();
fdt.Interval = FluentDateTime.DateInterval.Years;
fdt.Increment = inc;
return fdt;
}
//测试程序
DateTime testDate1 = new DateTime(2015, 3, 3);
DateTime testDate2 = new DateTime(2015, 3, 4);
Console.WriteLine(
string.Format("{0} is within 5 days of {1}? {2} (should be true)",
testDate1.ToShortDateString(), testDate2.ToShortDateString(), testDate1.IsWithIn(5.Days()).Of(testDate2)
));
testDate1 = new DateTime(2015, 3, 1);
testDate2 = new DateTime(2015, 3, 7);
Console.WriteLine(
string.Format("{0} is within 3 days of {1}? {2} (should be false)",
testDate1.ToShortDateString(), testDate2.ToShortDateString(), testDate1.IsWithIn(3.Days()).Of(testDate2)
));
testDate1 = new DateTime(2015, 3, 3);
testDate2 = new DateTime(2015, 4, 1);
Console.WriteLine(
string.Format("{0} is within 1 month of {1}? {2} (should be true)",
testDate1.ToShortDateString(), testDate2.ToShortDateString(), testDate1.IsWithIn(1.Months()).Of(testDate2)
));
testDate1 = new DateTime(2015, 3, 3);
testDate2 = new DateTime(2015, 6, 1);
Console.WriteLine(
string.Format("{0} is within 2 month of {1}? {2} (should be false)",
testDate1.ToShortDateString(), testDate2.ToShortDateString(), testDate1.IsWithIn(2.Months()).Of(testDate2)
));
IsWithin
必须 return 表示值范围的某种类型,记住 "centre" 和范围大小。现在 Of
可以是它的扩展方法,或者很容易成为普通实例方法,前提是您要自己编写类型。
请注意,3
并不清楚是 3 天、3 小时还是其他时间。你应该弄清楚你想如何指定它。您可以采用 TimeSpan
而不仅仅是 int
,或者使用单独的 IsWithinDays
、IsWithinHours
等方法。
一些事情:
- 我假设 within
{some time}
of 意味着{some time}
的任一侧 - 如果它只是指之后,代码就简单多了。保持我的假设意味着.IsWithin(x).Of
是可交换的,即a.IsWithin(x).Of(b) == b.IsWithin(x).Of(a)
. DateTimeRange
采用Func<DateTime, int, DateTime>
以避免重复代码(尽管如果我假设 a 则没有范围)
- 我不使用 TimeSpan 因为
The largest unit of time that the TimeSpan structure uses to measure duration is a day.
- Without hyperbole, this is the worst thing ever, and I hate myself a little for posting this. I would never write code like this in a professional context. I've only done this to (almost) satisfy @jason's requirements (I renamed
IsWithIn
toIsWithin
).
public static void Main()
{
var now = DateTime.Now;
var comparisonDate = now.AddMonths(-2);
bool within1Month = now.IsWithin(months: 1).Of(comparisonDate); // false
bool within2Months = now.IsWithin(months: 2).Of(comparisonDate); // true
bool within3Months = now.IsWithin(months: 3).Of(comparisonDate); // true
}
日期时间扩展:
public static class DateTimeExtensions
{
/// <summary>
/// <para>Specify exactly one of milliseconds, seconds, minutes, hours, days, months, or years.</para>
/// <para>Uses the first nonzero argument in the order specified.</para>
/// </summary>
public static DateTimeRange IsWithin(
this DateTime dateTime,
int milliseconds = 0, int seconds = 0, int minutes = 0, int hours = 0,
int days = 0, int months = 0, int years = 0)
{
if ( milliseconds != 0 )
return new DateTimeRange(dateTime, (_dateTime, _value) => _dateTime.AddMilliseconds(_value), milliseconds);
if ( seconds != 0 )
return new DateTimeRange(dateTime, (_dateTime, _value) => _dateTime.AddSeconds(_value), seconds);
if ( minutes != 0 )
return new DateTimeRange(dateTime, (_dateTime, _value) => _dateTime.AddMinutes(_value), minutes);
if ( hours != 0 )
return new DateTimeRange(dateTime, (_dateTime, _value) => _dateTime.AddHours(_value), hours);
if ( days != 0 )
return new DateTimeRange(dateTime, (_dateTime, _value) => _dateTime.AddDays(_value), days);
if ( months != 0 )
return new DateTimeRange(dateTime, (_dateTime, _value) => _dateTime.AddMonths(_value), months);
if ( years != 0 )
return new DateTimeRange(dateTime, (_dateTime, _value) => _dateTime.AddYears(_value), years);
throw new ArgumentException("At least one value must be nonzero");
}
}
日期时间范围:
/// <summary>
/// Represents a range between two DateTime values
/// </summary>
public struct DateTimeRange
{
private DateTime _min;
private DateTime _max;
public DateTime Min { get { return _min; } }
public DateTime Max { get { return _max; } }
/// <summary>
/// Uses generator to get the start and end dates of this range.
/// </summary>
/// <param name="middle">The midpoint of this DateTimeRange</param>
/// <param name="generator">Generates the min and max dates from the midpoint and a parameter</param>
public DateTimeRange(DateTime middle, Func<DateTime, int, DateTime> generator, int value)
{
_min = generator(middle, -value);
_max = generator(middle, +value);
}
public bool Of(DateTime dateTime)
{
return _min <= dateTime && dateTime <= _max;
}
}
我觉得有点惭愧 post 这是@jonskeet 回答的问题的唯一其他答案。