C#-为自动属性提供默认值与访问器时的行为差异

时间:2019-01-01 04:04:31

标签: c#

我试图理解为什么初始化顺序会在此处更改值。属性的访问者不应该返回默认的I / O指定的值。 谢谢。

void Main()
{
    Console.WriteLine(StartDate);
    Console.WriteLine(EndDate);
}

private static DateTime StartDate { get; } = new DateTime(EndDate.Year, 1, 1);

private static DateTime EndDate { get; } = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1).AddDays(-1);

此打印

1/1/0001 12:00:00 AM
31/12/2018 12:00:00 AM

void Main()
{
    Console.WriteLine(StartDate);
    Console.WriteLine(EndDate);
}

private static DateTime EndDate { get; } = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1).AddDays(-1);

private static DateTime StartDate { get; } = new DateTime(EndDate.Year, 1, 1);

打印

1/1/2018 12:00:00 AM
31/12/2018 12:00:00 AM

如果我将属性更改为

private static DateTime EndDate { get => new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1).AddDays(-1); }

private static DateTime StartDate { get => new DateTime(EndDate.Year, 1, 1); }

private static DateTime StartDate => new DateTime(EndDate.Year, 1, 1);

private static DateTime EndDate => new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1).AddDays(-1);

我得到一致的值,而不管它们指定的顺序如何。

2 个答案:

答案 0 :(得分:2)

这有两部分。

首先,.NET将第一个示例转换为静态构造函数,并按照声明的顺序初始化每个变量。

第二,.NET中的所有类字段在运行代码之前都初始化为其默认值。

因此,当您使用EndDate时,它已设置为其默认值,但尚未运行它的初始化程序。您正在访问其默认值。本质上,您正在生成以下代码:

class App
{
    static readonly DateTime _startDate, _endDate;

    static DateTime StartDate => _startDate;
    static DateTime EndDate => _endDate;

    static App()
    {
        // this code is put here implicitly by .NET

        _startDate = default;
        _endDate = default;

        // and this code is put here by C#,
        // translated from your initializers,
        // in the order they were declared.

        _startDate = new DateTime(_endDate.Year, 1, 1);
        _endDate = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1).AddDays(-1);
    }
}

答案 1 :(得分:0)

静态初始化程序按照它们在代码中给出的顺序执行,并且仅执行一次,因此为什么第一个代码块将EndDate属性视为{{1 }}(即DateTime)。

最后一个代码块没有初始化程序,它是expression-bodied member,实际上是一个完整的方法的简写形式,该方法在您每次调用属性时都会执行。例如:

1/1/0001 12:00:00 AM