0

I want to pass a delegate declaration to a class that will later be assigned by a different class and then later invoked by the first class. I get a NullReferenceException at the line indicated in the code below. How can I change the code to get the desired behavior?

class FirstClass
    {
        public Func<bool> funct;

        public FirstClass(Func<bool> funct)
        {
            this.funct = funct;
        }

        public void callFunc()
        {
            funct.Invoke();  // NullReferenceException
        }
    }

    class Program
    {
        public static Func<bool> testFunction;

        static void Main(string[] args)
        {
            FirstClass firstClassInstance = new FirstClass(testFunction);

            var secondClassInstance = new SecondClass();

            firstClassInstance.callFunc();
        }
    }

    class SecondClass
    {
        public SecondClass()
        {
            Program.testFunction = isManipUnderCursor;
        }

        private bool isManipUnderCursor()
        {
            return true;
        }
    }

2 Answers2

2

If you want to invoke whatever is the current value of Program.testFunction, invoke Program.testFunction

    public void callFunc()
    {
        Program.testFunction?.Invoke();  
    }

Or you provide a code that changes the value of what FirstClass.funct is, and call that:

class FirstClass{
  ...
  public void ChangeFuncTo(Func<bool> newFunc){
    funct = newFunc;
  }
  ...
}


        FirstClass firstClassInstance = new FirstClass(testFunction);

        var secondClassInstance = new SecondClass();

        firstClassInstance.ChangeFuncTo(Program.funct);

This whole thing you've arranged is fairly terrible in terms of structure, encapsulation and coherent class responsibilities. It would be good if you could post an actual use case for what the true aim is, so we can advise, but in general you should treat funcs like data; if you only know what operation you want firstclass's func to perform after you have finished constructing and using some other object, don't rely on a static to pass the new func around; provide and call a method on the first class to set the new behavior. Strive to find ways of avoiding static in your code.

        //we need to make FirstClass for some reason, before we can generate the fun it will use
        FirstClass firstClassInstance = new FirstClass();

        //second class is a func generator
        var secondClassInstance = new SecondClass();
        
        //now we can generate the func and set it
      

firstClassInstance.ChangeFuncTo(secondClassInstance.GetNewFunc());

Or

        //second class is a func generator, it can generate before firstclass is made
        var secondClassInstance = new SecondClass();
        
        //now we can generate the func and set it
        FirstClass firstClassInstance = new FirstClass(secondClassInstance.GetFunc());

In C# you can't "change what some simple variable points to, by changing what some other simple variable points to". To explain it in simpler terms of good old data:

string first = "this is the first string";
string second = first
first = "something else";

second will still refer to that value of "this is the first string". When you establish extra references, they don't chain. When you write string first = "this is the first string"; it gives us memory like this:

first --> "this is the first string"

Then you write string second = first which gives us memory like this:

first --> "this is the first string" <-- second

Finally you write first = "something else" which gives us memory like:

          "this is the first string" <-- second

first --> "something else"

Changing first never affected second. When writing string second = first you don't end up with chained references in memory, like this:

second --> first --> "this is the first string" 

such that altering first would cause second to see it:

second --> first --.    //"this is the first string" garbage collected
                    `-> "something else" 
Caius Jard
  • 72,509
  • 5
  • 49
  • 80
0

When you pass testFunction to FirstClass, it is null because testFunction has not been initialized or assigned. In this case, the reference passed doesn't point to the future home of the value, but it points to null and always will.

John Glenn
  • 1,469
  • 8
  • 13