6

Here is an example of a property I have, coded as simply as possible

private IEnumerable<int> _blocks;
private bool _blocksEvaluated;
public IEnumerable<int> Blocks
{
    get
    {
        if (!_blocksEvaluated)
        {
            _blocksEvaluated = true;
            _blocks = this.CalculateBlocks(0).FirstOrDefault();
        }
        return _blocks;
    }
}

This is verbose; I would like to make it more concise if possible. The following would be acceptable...

private Lazy<IEnumerable<int>> _blocks = 
    new Lazy<IEnumerable<int>>(() => this.CalculateBlocks(0).FirstOrDefault());

... but it doesn't compile.

Keyword 'this' is not valid in a static property, static method, or static field initializer

So I came up with the following

struct MyLazy<TResult>
{
    private bool evaluated;
    private TResult result;

    public TResult Evaluate(Func<TResult> func)
    {
        if (!evaluated)
        {
            evaluated = true;
            result = func();
        }
        return result;
    }
}

private MyLazy<IEnumerable<int>> _blocks;
public IEnumerable<int> Blocks
{
    get { return _blocks.Evaluate(() => this.CalculateBlocks(0).FirstOrDefault()); }
}

Which I like best, but is there a better way?

Note - I realize that mutable structs are usually evil, but they seem really useful for this one particular problem.

default.kramer
  • 5,943
  • 2
  • 32
  • 50

2 Answers2

7

Just initialize your field in the constructor.

public class MyClass
{
    public MyClass()
    {
        _blocks = new Lazy<IEnumerable<int>>(() => this.CalculateBlocks(0).FirstOrDefault());
    }

    private readonly Lazy<IEnumerable<int>> _blocks;
}
Michael Gunter
  • 12,528
  • 1
  • 24
  • 58
  • This is, of course, correct. Unfortunately now I'm getting really annoyed by [this problem](http://stackoverflow.com/q/4460206/644812), so I might just use my custom struct anyway. – default.kramer Aug 08 '13 at 00:13
5

You can't use this when initializing an instance field, but you can simply initialize it in the constructor to address that.

private Lazy<IEnumerable<int>> _blocks;

public MyClass()
{
   _blocks = new Lazy<IEnumerable<int>>(
         () => this.CalculateBlocks(0).FirstOrDefault());
}

public IEnumerable<int> Blocks
{
    get
    {
        return _blocks.Value;
    }
}
Femaref
  • 60,705
  • 7
  • 138
  • 176
Servy
  • 202,030
  • 26
  • 332
  • 449