Accessing a non-static member via Lazy<T> or any lambda expression

C#.Net.Net 4.0Lazy Evaluation

C# Problem Overview


I have this code:

public class MyClass
{
    public int X { get; set; }
    public int Y { get; set; }

    private Lazy<int> lazyGetSum = new Lazy<int>(new Func<int>(() => X + Y));
    public int Sum{ get { return lazyGetSum.Value; } }

}

Gives me this error:

> A field initializer cannot reference the non-static field, method, or > property.

I think it is very reasonable to access a non-static member via lazy, how to do this?

*** EDIT ***

The accepted answer solves the problem perfectly, but to see the detailed and in-depth -as always- reason of the problem you can read Joh Skeet's answer.

C# Solutions


Solution 1 - C#

You can move it into constructor:

private Lazy<int> lazyGetSum;
public MyClass()
{
   lazyGetSum = new Lazy<int>(new Func<int>(() => X + Y));
}

See @JohnSkeet answer below for more details about the reason of the problem. https://stackoverflow.com/questions/14029425/accessing-a-non-static-member-via-lazyt#14029456

Solution 2 - C#

Here's a simplified version of your problem:

class Foo
{
    int x = 10;
    int y = this.x;
}

And a slightly less simplified one:

class Foo
{
    int x = 10;
    Func<int> y = () => this.x;
}

(The this is usually implicit, but I've made it explicit here for the sake of clarity.)

In the first case, the use of this is very obvious.

In the second case, it's slightly less obvious, because it's deferred due to the lambda expression. It's still not allowed though... because the compiler would try to build a delegate which used this as the target, like this:

class Foo
{
    int x = 10;
    Func<int> y = this.GeneratedMethod;
    
    private int GeneratedMethod()
    {
        return x;
    }
}

This is prohibited by section 10.5.5.2 of the C# 5 spec:

> A variable initializer for an instance field cannot reference the instance being created.

The simplest fix is just to put the initialization in the constructor body, where you are able to refer to this. So in your code:

public class MyClass
{
    public int X { get; set; }
    public int Y { get; set; }

    private Lazy<int> lazyGetSum;

    public MyClass()
    {
        lazyGetSum = new Lazy<int>(() => X + Y);
    }

    public int Sum{ get { return lazyGetSum.Value; } }
}

Note that I've simplified the lambda expression as well - it's very rarely worth using new Func<int>(...).

Solution 3 - C#

The error is telling you exactly what is wrong. You can't access a property in a Field Initializer.

Suppose your class is like:

public class MyClass
{
    public int X { get; set; }
    public int Y { get; set; }

    private Lazy<int> lazyGetSum = new Lazy<int>(new Func<int>(() => 2 + 3));
    public int Sum { get { return lazyGetSum.Value; } }

}

Then it would compile without any problem. Since in your code you are accessing property X and Y in field initialization. You are getting the error.

You can also initialize them in constructor if you want:

public class MyClass
{
    public int X { get; set; }
    public int Y { get; set; }

    private Lazy<int> lazyGetSum; 
    public int Sum { get { return lazyGetSum.Value; } }

    public MyClass()
    {
        lazyGetSum = new Lazy<int>(new Func<int>(() => X + Y));
    }

}

Solution 4 - C#

I think you need to define static your fields to use it like this;

public  class MyClass
    {
        public static int X { get; set; }
        public static int Y { get; set; }

        private Lazy<int> lazyGetSum = new Lazy<int>(new Func<int>(() => X + Y));
        public int Sum { get { return lazyGetSum.Value; } }
    }

And of course, you need to initialize your fields. You can't do it with other way.

EDIT: Or you can define in with your constructor without any defining static.

public MyClass()
    {
        lazyGetSum = new Lazy<int>(new Func<int>(() => X + Y));
    }

with

private Lazy<int> lazyGetSum; 
public int Sum { get { return lazyGetSum.Value; } }

Solution 5 - C#

If you want to use the non static method. You can also use a build alternative for Lazy self that gets the Func parameter in the .Value and not in the constructor like Lazy.

You code would look like this:

public class MyClass
{
    public int X { get; set; }
    public int Y { get; set; }

    private readonly LazyValue<int> lazyGetSum = new LazyValue<int>();
    public int Sum { get { return lazyGetSum.GetValue(() => X + Y); } }
}

It implements the property in the property. Just where you might expect it,

Solution 6 - C#

Found this question when I had a similar issue, and wanted to find a good pattern to use.

The issue with "move the initialisation to the constructor" suggested in other answers is that the lambda for the initialization function now appears in the constructor (and indeed an explicit constructor is now required in a class which didn't previously need one).

Fine for this toy example, but in a more complicated class with many properties, it is useful to have all the logic relating to the property in one place.

Alex Siepman's answer suggests a neat alternative, but the third party site hosting the LazyValue<> class seems to be "Service unavailable" right now, and in any case I wasn't looking for a third party solution, merely an efficient pattern to use with the normal Lazy<> class. I'm also concerned that in some use cases, creating the delegate instance and associated closure each time the property is accessed may be non-trivial.

Having a line in the constructor seems unavoidable, due to the issues highlighted in other answers, but it seems preferable to me to avoid putting the property logic in the constructor itself, as it will be so far separated from the property in any diffs etc.

The following 2 patterns seem to work, but I'm not sure whether there's an even better alternative I missed.

Pattern 1: don't bother using a lambda - declare an real function next to the property, and wrap it in an implicit delegate:

public class MyClass
{
  public MyClass()
  {
    lazyGetSum = new Lazy<int>(GetSum);
  }

  public int X { get; set; }
  public int Y { get; set; }

  private Lazy<int> lazyGetSum;
  public int Sum { get { return lazyGetSum.Value; } }
  private int GetSum() { return X + Y; }
}

Pattern 2: Declare a property init function and call that from the constructor.

public class MyClass
{
  public MyClass()
  {
    LazyGetSumInit();
  }

  public int X { get; set; }
  public int Y { get; set; }

  private Lazy<int> lazyGetSum;
  public int Sum { get { return lazyGetSum.Value; } }
  private void LazyGetSumInit() { lazyGetSum = new Lazy<int>(new Func<int>(() => X + Y)); }
}

Seeing the two side by side, I think I prefer the second, except for the seemingly clumsy name for the function.

[In my real implementation, I had a name similar to InitSum, so that it's an implementation detail of the property that it's "lazy", and it can in principle be changed between a lazy and non-lazy implementation without changing the constructor code]

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSawanView Question on Stackoverflow
Solution 1 - C#JleruOHePView Answer on Stackoverflow
Solution 2 - C#Jon SkeetView Answer on Stackoverflow
Solution 3 - C#HabibView Answer on Stackoverflow
Solution 4 - C#Soner GönülView Answer on Stackoverflow
Solution 5 - C#Alex SiepmanView Answer on Stackoverflow
Solution 6 - C#SteveView Answer on Stackoverflow