我有以下抽象类:
public abstract class Period
{
public int Id { get; set; }
protected abstract DateTimeOffset StartDate { get; set; }
protected abstract DateTimeOffset EndDate { get; set; }
}
通过以下实现:
public class MonthlyPeriod : Period
{
private DateTimeOffset startDate { get; set; }
public MonthlyPeriod(DateTimeOffset startDate)
{
this.startDate = startDate;
}
protected override DateTimeOffset EndDate
{
get
{
return startDate.AddMonths(1).AddTicks(-1);
}
set
{
startDate = new DateTime(value.Year, value.Month, 1);
}
}
protected override DateTimeOffset StartDate
{
get
{
return startDate;
}
set
{
startDate = new DateTimeOffset(value.Year, value.Month, 1, 0, 0, 0, value.Offset);
}
}
}
我想做的是在抽象类中包含以下抽象方法:
public abstract Period GetPreviousPeriod();
public abstract Period GetNextPeriod();
然后在实现中让它们具体返回MonthlyPeriod
:
public override MonthlyPeriod GetNextPeriod() => new MonthlyPeriod(EndDate.AddDays(1));
public override MonthlyPeriod GetPreviousPeriod() => new MonthlyPeriod(StartDate.AddDays(-1));
然而,这有一个明显的缺陷,即我将抽象类中的方法类型指定为Period
,而不是MonthlyPeriod
。
有没有一种直接的方法来定义这种类型的关系?
到目前为止,我得到的最好的解决方案是:
- 将抽象方法从
public
切换到protected
。 - 根据需要使实现的抽象方法产生
Period
。 在抽象类中定义以下方法:
public T GetPreviousPeriod<T>() where T : Period { T prevPeriod = GetPreviousPeriod() as T; if (prevPeriod == null) { throw new ArgumentException(); } return prevPeriod; } public T GetNextPeriod<T>() where T : Period { T nextPeriod = GetNextPeriod() as T; if (nextPeriod == null) { throw new ArgumentException(); } return nextPeriod; }
这有效;但是,它不一定是一个完整的解决方案。特别是,它缺少编译时承诺类型是正确的。
如果您创建一些扩展方法,这些方法创建这些新实例并返回它们,而不是在基类上强制使用该方法会怎么样?
此外,句号也作为"周期工厂"工作看起来不对,因为它违反了 SOLID 中的 S。
public static MonthlyPeriod GetNextPeriod(this MonthlyPeriod period)
{
return new MonthlyPeriod(period.EndDate);
}
想出了一个在我的原始问题背景下工作的解决方案。
- 将
Period
更改为Period<T> where T : Period<T>
- 将
public abstract Period GetPreviousPeriod();
更改为public abstract T GetPreviousPeriod();
- 重复 2 表示
GetNextPeriod()
。 - 将
MonthlyPeriod : Period
更改为MonthlyPeriod : Period<MonthlyPeriod>
。
您可以定义一个像 IPeriod 这样的接口,并将其作为接口方法中的返回类型。然后,您可以返回MonthlyPeriod,这将实现接口IPeriod