使用属性进行延迟初始化的方法

发布于 2024-10-10 20:20:25 字数 910 浏览 10 评论 0原文

我目前正在更改一个广泛使用的类,以将尽可能多的昂贵初始化从类构造函数转移到延迟初始化属性中。下面是一个示例(在 C# 中):

之前:

public class ClassA
{
    public readonly ClassB B;

    public void ClassA()
    {
        B = new ClassB();
    }
}

之后:

public class ClassA
{
    private ClassB _b;

    public ClassB B
    {
        get
        {
            if (_b == null)
            {
                _b = new ClassB();
            }

            return _b;
        }
    }
}

我正在更改的类中还有相当多的这些属性,其中一些在某些上下文中没有使用(因此是惰性),但如果使用它们,它们就会可能会被重复调用。

不幸的是,这些属性也经常在类内部使用。这意味着私有变量 (_b) 有可能在不初始化的情况下直接被方法使用。

有没有办法只让公共属性(B)在类中可用,或者甚至是具有相同的需要时初始化的替代方法?

这是从程序员转发的(显然不够主观): https://softwareengineering.stackexchange.com/questions/34270/best-带属性的延迟初始化方法

I'm currently altering a widely used class to move as much of the expensive initialization from the class constructor into Lazy Initialized properties. Below is an example (in c#):

Before:

public class ClassA
{
    public readonly ClassB B;

    public void ClassA()
    {
        B = new ClassB();
    }
}

After:

public class ClassA
{
    private ClassB _b;

    public ClassB B
    {
        get
        {
            if (_b == null)
            {
                _b = new ClassB();
            }

            return _b;
        }
    }
}

There are a fair few more of these properties in the class I'm altering, and some are not used in certain contexts (hence the Laziness), but if they are used they're likely to be called repeatedly.

Unfortunately, the properties are often also used inside the class. This means there is a potential for the private variable (_b) to be used directly by a method without it being initialized.

Is there a way to make only the public property (B) available inside the class, or even an alternative method with the same initialized-when-needed?

This is reposted from Programmers (not subjective enough apparently):
https://softwareengineering.stackexchange.com/questions/34270/best-methods-for-lazy-initialization-with-properties

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

二手情话 2024-10-17 20:20:25

好吧,我推荐的解决方案是告诉你的同事使用该财产,而不是该字段。但你可以在某种程度上防止白痴这样做:

public class ClassA
{
    private Lazy<ClassB> _b = new Lazy<ClassB>(() => new ClassB());

    public ClassB B
    {
        get
        {
            return _b.Value;
        }
    }
}

现在很难搞砸了。

Well, my recommended solution would be to tell your coworker to use the property, not the field. But you could idiot-proof it to some degree like this:

public class ClassA
{
    private Lazy<ClassB> _b = new Lazy<ClassB>(() => new ClassB());

    public ClassB B
    {
        get
        {
            return _b.Value;
        }
    }
}

Now it's pretty hard to screw up.

橘虞初梦 2024-10-17 20:20:25

您可以考虑将惰性属性推入基类中,以避免直接访问支持变量。我知道并不理想。我一直认为这是 C# 所缺乏的东西,即对惰性属性的直接支持。

You could consider pushing the lazy properties into a base class to avoid direct access to the backing variable. Not ideal I know. I've always thought this was something lacking in C# i.e. direct support for lazy properties.

陌上芳菲 2024-10-17 20:20:25

@chibacity 发布(随后)删除了[后来又取消删除:P]使用抽象基类的替代选项。虽然它在代码分发方面可能并不理想,但它确实提供了一个很好的封装,消除了大量混乱的代码,从而形成更干净、更简洁的 ClassA。例如,您可以考虑结合使用这些技术来实现这两个目标:

public class ClassB { /* Class to be lazily instantiated */ }

public abstract class BaseA
{
    private Lazy<ClassB> _b = new Lazy<ClassB>(() => new ClassB());
    public virtual ClassB B { get { return _b.Value; } }
}

public class ClassA : BaseA
{
    public override ClassB B { get { return base.B; } }
}

乍一看,这似乎比较冗长,但是当您考虑 ClassA 是您将在其中工作并使用的类时,这现在意味着所有您的引用将通过相同的属性 - 没有多余的不必要字段导致潜在的混乱,没有绕过该属性直接引用 _b 并且无需告诉您的同事使用哪个...只有一个。

我并不是说这是正确的方法,也不是说这是应该遵循或不应该遵循的模式,我只是指出 @chibacity 建议的优点,否则可能会被忽视。

如果您可以拥有隐式延迟加载属性而不必引用 B.Value... 例如:

[Lazy]
public ClassB B { get; }

或者对于没有无参数构造函数的对象

[Lazy(() => new ClassB("Hello", "World"))]
public ClassB B { get; }

,或者可能像@chibacity 在评论中建议的那样

public ClassB B { lazyget; }

,或者

public ClassB B { lazyget : new ClassB(); }

唉,我不认为有任何其中目前有任何形式的可用解决方案......

@chibacity posted (and subsequently) deleted [and later undeleted :P] an alternative option using an abstract base class. While it may not be ideal in terms of code distribution it does provide a nice encapsulation removing a lot of code clutter making for a cleaner and more succinct ClassA. For instance, you could consider combining the techniques to achieve both goals:

public class ClassB { /* Class to be lazily instantiated */ }

public abstract class BaseA
{
    private Lazy<ClassB> _b = new Lazy<ClassB>(() => new ClassB());
    public virtual ClassB B { get { return _b.Value; } }
}

public class ClassA : BaseA
{
    public override ClassB B { get { return base.B; } }
}

At first glance, it seems like this is more long winded, but when you consider that ClassA which is the class you would be working in and with, this now means that all your references are going through the same property - there is no extraneous unnecessary field causing potential confusion, there's no bypassing the property to reference _b directly and there's no need to tell your coworker which to use... there's only one.

Not saying this is the right way to do this or that this is a pattern that should or shouldn't be followed, I'm just pointing out the advantages of what @chibacity suggested that may otherwise go unnoticed.

It would be nice if you could have implicit lazy loaded properties without having to refer to B.Value... for instance:

[Lazy]
public ClassB B { get; }

or for objects without parameterless constructors

[Lazy(() => new ClassB("Hello", "World"))]
public ClassB B { get; }

or perhaps as @chibacity suggested in a comment

public ClassB B { lazyget; }

or

public ClassB B { lazyget : new ClassB(); }

Alas, I don't think any of these are currently available solutions in any form...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文