-1

The following code creates a dictionary with Actions.

class Test
{
    private Dictionary<string, Action> ActionLookup = new();

    public Test()
    {
        ActionLookup.Add("key", SampleAction);
    }

    protected virtual void SampleAction()
    {
        // Do something useful here...
    }
}

That code works. However, the following version gives me a compile error.

class Test
{
    private Dictionary<string, Action> ActionLookup = new()
    {
        ["key"] = SampleAction  // ERROR CS0236
    };

    protected virtual void SampleAction()
    {
        // Do something useful here...
    }
}

Error CS0236 A field initializer cannot reference the non-static field, method, or property

Why can't I add SampleAction to my dictionary using a collection initializer when it's perfectly valid to add it manually?

I know I can workaround it using something like the following, but why is this necessary?

class Test
{
    private Dictionary<string, Action<MyClass>> ActionLookup = new()
    {
        ["key"] = o => o.SampleAction()
    };

    protected virtual void SampleAction()
    {
        // Do something useful here...
    }
}

Note: It's not an option to make SampleAction static because I need it to be virtual.

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
  • 3
    Does this answer your question? [A field initializer cannot reference the nonstatic field, method, or property](https://stackoverflow.com/questions/14439231/a-field-initializer-cannot-reference-the-nonstatic-field-method-or-property) Just put the whole initializer into the constructor of `Test` – Charlieface Nov 09 '21 at 21:12

1 Answers1

0

This is happening because the context you are accessing the SampleAction changes. In the first code it is an instance method, in the second code it's field initializer.

There is one simple workaround which is turning ActionLookup into a property by using expression bodies (notice the => instead of =):

private Dictionary<string, Action> ActionLookup => new()
{
    ["key"] = SampleAction  // ERROR CS0236
};

But, this will create the dictionary every time you access the property.

You can fix it by using a backing field for it:

private Dictionary<string, Action> _actionLookup;

private Dictionary<string, Action> ActionLookup
{
     get
     {
          if (_actionLookup != null)
          {
              _actionLookup = new Dictionary<string, Action>() { ["key"] = SampleAction };
          }

          return _actionLookup;
     }
}

I know a lot of workarounds going on here and your workaround may be simpler than this, but it's just another way to make it work. But I don't think it is worth just to get a simpler syntax.

Selman Genç
  • 100,147
  • 13
  • 119
  • 184
  • Thanks, but I'm not sure what the root difference is between an instance method being used to initialize a field and a field initializer. Why is it not still an instance method? – Jonathan Wood Nov 09 '21 at 21:26
  • @JonathanWood you can check this answer that explains it in detail: https://stackoverflow.com/a/57762805/3010968 – Selman Genç Nov 09 '21 at 21:27