Search code examples
c#classlambdadelegatesclass-members

Why a lambda delegate declared as an instance field can only access static members?


I have this:

public class Demo {

    private IService _service;
    
    Action<Guid> action = v => _service.CallServiceWithParameter(v);

}

I get error:

Cannot access non-static field '_service' in static context

huh? Where is the static context and why is a lambda forced to be static? the lambda itself is not static...


Solution

  • Field initializers are static statements that are evaluated before the constructor is executed, which is why they can only access other static items.

    You can see this if you try to replace the initializer with a method call; it will only compile if you make that method static.

    Here is a runnable Demo fiddle: https://dotnetfiddle.net/IVtMHJ

    Code from the fiddle:

    using System;
    
    public class Program
    {
        public static void Main()
        {
            Console.WriteLine("Demo is going to be created");
            var d = new Demo();
            Console.WriteLine("Demo has been created");
        }
    }
    
    public class Demo
    {
        public Demo()
        {
            Console.WriteLine("Running constructor");
        }
    
        private IService _service;
        
        Action<Guid> action = CreateAction();
        
        public static Action<Guid> CreateAction() // Will get compile error above if we remove "static" here
        {
            Console.WriteLine("Running CreateAction");
            return null;
        }
    }
    
    public interface IService { }
    

    Output:

    Demo is going to be created
    Running CreateAction
    Running constructor
    Demo has been created

    If you move the CreateAction call into the constructor then you can make it non-static:

    public Demo()
    {
        Console.WriteLine("Running constructor");
        action = CreateAction();
    }
    
    private IService _service;
    
    Action<Guid> action;
    
    public Action<Guid> CreateAction() // Now it does not need to be "static"
    {
        Console.WriteLine("Running CreateAction");
        return null;
    }
    

    Output (from fiddle):

    Demo is going to be created
    Running constructor
    Running CreateAction
    Demo has been created