I've just stumbled upon a weird issue when trying to convert from anonymous function to a method group. The example below illustrates the issue perfectly - there are 2 methods - Run() and Crash() which do everything the same, except for using Anonymous Function vs Method Group.
Basically the issue is that I would like to create a Func to call a method on an object, which is not initialized on application start and instead comes later, BEFORE this func is ever run. Using an Anonymous Function works great, but converting to a Method Group causes an exception.
It's not really a big deal to stick to Anonymous Function instead of a Method Group, however a roslynator warning RCS1207 came up and I would like to understand the cause of this issue first, before simply disabling it with an inline comment.
namespace AnonymousFunctionVsmethodGroup
{
class Program
{
static void Main(string[] args)
{
var app = new App();
app.Run();
app.Crash();
}
}
public class App
{
private Func<string> m_Func;
public void Run()
{
Entity cat = null;
// Anonymous function. At this point cat is null
m_Func = () => cat.GetName();
// Initializing new cat
cat = new Entity("Cat");
// Func is executed on a valid cat
Console.WriteLine(m_Func());
Console.Read();
}
public void Crash()
{
Entity cat = null;
// Method group. At this point cat is null. Code never gets through here and an exception is thrown instead.
// "Delegate to an instance method cannot have null this"
m_Func = cat.GetName;
// Initializing new cat
cat = new Entity("Cat");
// Func is executed on a valid cat?
Console.WriteLine(m_Func());
Console.Read();
}
}
// Sample entity
public class Entity
{
private string name;
public Entity(string name)
{
this.name = name;
}
public string GetName()
{
return name;
}
}
}
When you assign a "Method Group", the delegate associated with the object will be called immediately. However, the lambda creates an additional redirection: The code will first call store an anonymous reference to a method on an object that may not exist, and takes zero, one, or more parameters and turn calls Facade.Entity.GetName with that parameter. In your case, it doesn't pass any parameter to the method delegate, but as long as you don't execute the anonymous method, it only represents a signature for a method call on a class.
If you look at the definition of Anonymous methods, "they are methods without a name. We can write small method block without any name and assign its address to the delegate object, then this delegate object is used to call it."