【问题标题】:Lazily evaluated property syntax difference懒惰评估的属性语法差异
【发布时间】:2023-03-28 07:02:01
【问题描述】:

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

// (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;
}

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

【问题讨论】:

  • 是的,第二个没有效果,因为它将构造惰性对象,然后立即评估它。属性后的= xxx语法初始化属性值,这会强制惰性对象立即求值。
  • @LasseVågsætherKarlsen 这就是我的想法。谢谢你说清楚。
  • 虽然知道第一个也不起作用,但你想要这个:public static Foo Instance =&gt; instance.Value;
  • 所以在这方面,不,它们没有什么不同 :) 但它们也没有按预期工作(我希望)。
  • 这是因为您使用= new Lazy&lt;Foo&gt;().ValueInstance 分配了一个值,并且在初始化Foo 时对其进行了评估。相比之下,Lasse 的建议是有效地为属性的get 方法编写一个实现。

标签: c# lazy-evaluation lazy-initialization


【解决方案1】:

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

但是,这只是一个假设,请注意,它们也没有工作,至少不是我希望你想要的那样。

你看,这个语法:

<property declaration> = <expression>;

为属性声明一个初始化器,它将在构造所属类型时执行。

所以这个:

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

一点也不懒。它将声明并构造一个 Lazy&lt;Foo&gt; (尽管您可能在这里也错过了 getter 委托,即使它可以编译),但是当您声明该属性时,您最终会在构造拥有类型时评估惰性对象的属性因此它变得非懒惰。

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

正确的方法,这只能通过第一种语法形式来实现,是使用不带初始化器的属性,或者这样:

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

或者这个:

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

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

private static readonly Lazy<Foo> instance = new Lazy<Foo>();
public static Foo Instance => instance.Value;

这将声明一个 getter body,直到您实际读取该属性后才会执行。


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

【讨论】:

  • 谢谢,我会尽快接受。这是一个很好的答案,只是一个简单的问题:使用没有支持字段的表达式主体属性语法(即public static Foo Instance =&gt; new Lazy&lt;Foo&gt;().Value;)也不起作用,对吧?所以没有单行...?
  • 这将构造一个新的惰性对象,然后每次读取属性时立即评估它,所以不,这也行不通。那么最好只使用public static Foo Instance =&gt; MethodThatEvaluatesToFoo(); 就我所知,这没有唯一的方法。
【解决方案2】:

除了Lasse Vågsæther Karlsen给出的优秀answer之外,我想进一步推测并假设OP是在Singleton实现之后。这是一种完全惰性的方法。

Approach 1
public sealed class Singleton {
    //Private ctor of course :P
    private Singleton() {}
    // Instance property to access Singleton Instance
    public static Singleton Instance { get { return Nested.instance; } }

    private class Nested {

        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static Nested() { }

        internal static readonly Singleton instance = new Singleton();
    }
}

Approach 2
public sealed class Singleton
{
    private static readonly Lazy<Singleton> lazy =
        new Lazy<Singleton>(() => new Singleton());

    public static Singleton Instance { get { return lazy.Value; } }

    private Singleton()
    {
 }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-01-07
    • 1970-01-01
    • 2015-09-06
    • 2016-12-14
    • 2021-12-25
    • 2018-04-01
    • 2018-03-31
    • 1970-01-01
    相关资源
    最近更新 更多