我对延迟加载的方法有缺陷吗?

时间:2023-01-15 22:56:37

Platform: Visual Studio 2008 SP1 with Resharper 4.1, .NET 3.5

平台:带有Resharper 4.1,.NET 3.5的Visual Studio 2008 SP1

I have a class with a static method, GetProperty<T> that returns a property value lazily.

我有一个带有静态方法的类,GetProperty 可以懒惰地返回属性值。

private static T GetProperty<T>(T backingField, Func<T> factory) 
    where T : class 
{
    if (backingField == null)
        backingField = factory();
    return backingField;
}

But when I use above method to return a property, I am getting two warnings that says that private backing fields are not assigned. But they are assigned later on only when they are needed.

但是,当我使用上述方法返回属性时,我收到两条警告,指出未分配私有支持字段。但是只有在需要时才会分配它们。

我对延迟加载的方法有缺陷吗?

Is this warning ignorable?
-- Or --
Is my appoach to loading a property flawed?

这个警告是否可以忽略? - 或者 - 我的加载财产是否存在缺陷?

4 个解决方案

#1


Your method is flawed. To take this approach you need to make backingField a ref parameter.

你的方法有缺陷。要采用这种方法,您需要使backingField成为ref参数。

private static T GetProperty<T>(ref T backingField, Func<T> factory)

Then on GetProperty, pass ref _ImagXpress or ref _PdfXpress.

然后在GetProperty上传递ref _ImagXpress或ref _PdfXpress。

The way you're doing it now just assigns a new value to the parameter, not to the actual backing field.

你现在这样做只是为参数赋予一个新值,而不是为实际的后备字段赋值。

#2


Your approach is flawed. You're fields will never be set to anything. the backingField argument is being set in the GetProperty<T> method, but this does not update the field you're passing in. You'll want to pass in that argument with the ref keyword attached to it like this:

你的方法有缺陷。你的字段永远不会被设置为任何东西。 backingField参数是在GetProperty 方法中设置的,但是这不会更新您传入的字段。您将要传递带有ref关键字的参数,如下所示:

private static T GetProperty<T>(ref T backingField, Func<T> factory)

#3


As I stated in comments on another answer, the need for a ref parameter is a code smell. First of all, if you're doing this in a method, you're breaking the single responsibility principle, but more importantly, the code is only reusable within your inheritance heirarchy.

正如我在另一个答案的评论中所说,对参数的需求是代码气味。首先,如果你在一个方法中这样做,你就违反了单一责任原则,但更重要的是,代码只能在你的继承层中重复使用。

There's a pattern to be derived here:

这里有一个模式:

public class LazyInit<T>
    where T : class
{
    private readonly Func<T> _creationMethod;
    private readonly object syncRoot;
    private T _instance;

    [DebuggerHidden]
    private LazyInit()
    {
        syncRoot = new object();
    }

    [DebuggerHidden]
    public LazyInit(Func<T> creationMethod)
        : this()
    {
        _creationMethod = creationMethod;
    }

    public T Instance
    {
        [DebuggerHidden]
        get
        {
            lock (syncRoot)
            {
                if (_instance == null)
                    _instance = _creationMethod();
                return _instance;
            }
        }
    }

    public static LazyInit<T> Create<U>() where U : class, T, new()
    {
        return new LazyInit<T>(() => new U());
    }

    [DebuggerHidden]
    public static implicit operator LazyInit<T>(Func<T> function)
    {
        return new LazyInit<T>(function);
    }
}

This allows you to do this:

这允许您这样做:

public class Foo
{
    private readonly LazyInit<Bar> _bar1 = LazyInit<Bar>.Create<Bar>();
    private readonly LazyInit<Bar> _bar2 = new LazyInit<Bar>(() => new Bar("foo"));

    public Bar Bar1
    {
        get { return _bar1.Instance; }
    }

    public Bar Bar2
    {
        get { return _bar2.Instance; }
    }
}

#4


To propose a different solution:

提出一个不同的解决方案:

I'd say that you're not saving a whole lot by encapsulating that logic into a separate method. You're increasing your complexity without much gain. I'd suggest doing it this way:

我会说,通过将该逻辑封装到一个单独的方法中,你并没有节省很多。你增加了你的复杂性而没有多少收获。我建议这样做:

protected PdfXpress PdfXpress
{
    get
    {
        if (_PdfXpress == null)
            _PdfXpress = PdfXpressSupport.Create();

        return _PdfXpress;
    }
}

protected ImagXpress ImagXpress
{
    get
    {
        if (_ImagXpress == null)
            _ImagXpress = IMagXpressSupport.Create();

        return _ImagXpress;
    }
}

You're adding a few lines, but decreasing complexity considerably.

您添加了几行,但大大降低了复杂性。

#1


Your method is flawed. To take this approach you need to make backingField a ref parameter.

你的方法有缺陷。要采用这种方法,您需要使backingField成为ref参数。

private static T GetProperty<T>(ref T backingField, Func<T> factory)

Then on GetProperty, pass ref _ImagXpress or ref _PdfXpress.

然后在GetProperty上传递ref _ImagXpress或ref _PdfXpress。

The way you're doing it now just assigns a new value to the parameter, not to the actual backing field.

你现在这样做只是为参数赋予一个新值,而不是为实际的后备字段赋值。

#2


Your approach is flawed. You're fields will never be set to anything. the backingField argument is being set in the GetProperty<T> method, but this does not update the field you're passing in. You'll want to pass in that argument with the ref keyword attached to it like this:

你的方法有缺陷。你的字段永远不会被设置为任何东西。 backingField参数是在GetProperty 方法中设置的,但是这不会更新您传入的字段。您将要传递带有ref关键字的参数,如下所示:

private static T GetProperty<T>(ref T backingField, Func<T> factory)

#3


As I stated in comments on another answer, the need for a ref parameter is a code smell. First of all, if you're doing this in a method, you're breaking the single responsibility principle, but more importantly, the code is only reusable within your inheritance heirarchy.

正如我在另一个答案的评论中所说,对参数的需求是代码气味。首先,如果你在一个方法中这样做,你就违反了单一责任原则,但更重要的是,代码只能在你的继承层中重复使用。

There's a pattern to be derived here:

这里有一个模式:

public class LazyInit<T>
    where T : class
{
    private readonly Func<T> _creationMethod;
    private readonly object syncRoot;
    private T _instance;

    [DebuggerHidden]
    private LazyInit()
    {
        syncRoot = new object();
    }

    [DebuggerHidden]
    public LazyInit(Func<T> creationMethod)
        : this()
    {
        _creationMethod = creationMethod;
    }

    public T Instance
    {
        [DebuggerHidden]
        get
        {
            lock (syncRoot)
            {
                if (_instance == null)
                    _instance = _creationMethod();
                return _instance;
            }
        }
    }

    public static LazyInit<T> Create<U>() where U : class, T, new()
    {
        return new LazyInit<T>(() => new U());
    }

    [DebuggerHidden]
    public static implicit operator LazyInit<T>(Func<T> function)
    {
        return new LazyInit<T>(function);
    }
}

This allows you to do this:

这允许您这样做:

public class Foo
{
    private readonly LazyInit<Bar> _bar1 = LazyInit<Bar>.Create<Bar>();
    private readonly LazyInit<Bar> _bar2 = new LazyInit<Bar>(() => new Bar("foo"));

    public Bar Bar1
    {
        get { return _bar1.Instance; }
    }

    public Bar Bar2
    {
        get { return _bar2.Instance; }
    }
}

#4


To propose a different solution:

提出一个不同的解决方案:

I'd say that you're not saving a whole lot by encapsulating that logic into a separate method. You're increasing your complexity without much gain. I'd suggest doing it this way:

我会说,通过将该逻辑封装到一个单独的方法中,你并没有节省很多。你增加了你的复杂性而没有多少收获。我建议这样做:

protected PdfXpress PdfXpress
{
    get
    {
        if (_PdfXpress == null)
            _PdfXpress = PdfXpressSupport.Create();

        return _PdfXpress;
    }
}

protected ImagXpress ImagXpress
{
    get
    {
        if (_ImagXpress == null)
            _ImagXpress = IMagXpressSupport.Create();

        return _ImagXpress;
    }
}

You're adding a few lines, but decreasing complexity considerably.

您添加了几行,但大大降低了复杂性。