延迟评估属性语法差异

Tho*_*kow 0 c# lazy-evaluation lazy-initialization

对于延迟评估的属性,以下两种方法(具有支持字段的属性和具有默认值的属性)之间是否有任何差异,或者它们是否等效?

// (1)
public static class Foo
{
    private static readonly Lazy<Foo> instance = new Lazy<Foo>();
    public static Foo Instance { get; } = instance.Value;
}

// (2)
public static class Foo
{
    public static Foo Instance { get; } = new Lazy<Foo>().Value;
}
Run Code Online (Sandbox Code Playgroud)

我想要实现的是,Foo仅在访问 时创建 的实例Foo.Instance,而不是之前创建 - 更重要的是,当Foo.Instance从未访问过时,不应创建任何实例。

ang*_*son 5

嗯,实际上,不,它们没有不同。

但是,请注意,这只是一个假设,它们也不起作用,至少没有按照我希望的方式起作用。

你看,这个语法:

<property declaration> = <expression>;
Run Code Online (Sandbox Code Playgroud)

声明属性的初始值设定项,该属性将在构造所属类型时执行。

所以这:

private static readonly Lazy<Foo> instance = new Lazy<Foo>();
public static Foo Instance { get; } = instance.Value;
Run Code Online (Sandbox Code Playgroud)

一点也不懒。它将声明并构造一个Lazy<Foo>(尽管您可能在这里也缺少 getter 委托,即使它可以编译),但是当您声明该属性时,您最终会得到在构造所属类型时评估惰性对象的属性,因此它变得不懒惰。

第二个有完全相同的问题,您构造并立即评估惰性对象,使其变得非惰性。

正确的方法(只能以第一种语法形式实现)是使用不带初始值设定项的属性,可以是:

private static readonly Lazy<Foo> instance = new Lazy<Foo>();
public static Foo Instance
{
    get { return instance.Value; }
}
Run Code Online (Sandbox Code Playgroud)

或这个:

private static readonly Lazy<Foo> instance = new Lazy<Foo>();
public static Foo Instance
{
    get => instance.Value;
}
Run Code Online (Sandbox Code Playgroud)

或者可能是最好的,如下所示:

private static readonly Lazy<Foo> instance = new Lazy<Foo>();
public static Foo Instance => instance.Value;
Run Code Online (Sandbox Code Playgroud)

这将声明一个 getter主体,该主体在您实际读取该属性之前不会执行。


TL;DR总而言之,您给出的两个示例没有什么不同,但它们(可能)都是错误的,您需要更改属性声明来修复它。

  • 这将构造一个新的惰性对象,然后**每次读取属性**时立即评估它,所以不,这也不起作用。那么最好只是 `public static Foo Instance =&gt; MethodThatEvaluatesToFoo();` 据我所知,没有任何行话可以实现这一点。 (2认同)