2

I'm having problems getting my head around Action delegates in C#

I've looked at this question and I understand the examples there, but in the codebase that I'm working on it's used in a way that I don't quite get. This is the method using the action delegate:

public static string RenderTemplate<T>(string templatePath, T data)
{
    string result = null;
    ExecuteRazorMethod(() =>
    {
         result = Razor.Run(data, templatePath);
    });
    return result;
}

The call to ExecuteRazorMethod() will invoke the following method:

private static void ExecuteRazorMethod(Action a)
{
    try
    {
        a();
    }
   .
   .
   .//irrelevant code
   .
}

I don't understand what happens when a() is executed. What method is invoked? I've tried debugging it, and the value of a passed into the method is : Void <RenderTemplate> b__5

I don't get that. I need to know what actually happens to the two parametes in RenderTemplate but not understanding what/where the a() executes makes it hard. Is it maybe something about Anonymous types that I don't understand?

Community
  • 1
  • 1
Force444
  • 2,872
  • 7
  • 31
  • 70

3 Answers3

3

When a executes in ExecuteRazorMethod, it executes exactly the delegate you pass as a to ExecuteRazorMethod. Try to toggle the breakpoint at this line result = Razor.Run(data, templatePath); in this piece of code:

ExecuteRazorMethod(() =>
{
     result = Razor.Run(data, templatePath);
});

You will see, that when a starts to execute, your breakpoint will hit.

Max Tkachenko
  • 504
  • 1
  • 6
  • 17
  • Thanks but I still don't get how the variable result gets populated. I mean the 'data' parameter is some JSON data. Razor.Run(data, templatePath) ends up storing html representing that data in the variable result. How and WHERE is the html generated from the 'data', that's what I can't figure out. – Force444 Aug 11 '14 at 10:14
2

That code will be compiled to something more or less similar to this, I hope it becomes clear now:

[CompilerGenerated]
internal class Closure<T>
{
    public string Result {get; private set;}

    private readonly string _templatePath;
    private readonly T _data;

    public Closure(string templatePath, T data)
    {
      _templatePath = templatePath;
      _data = data;
    }

    public void DelegateMethod()
    {
      Result = Razor.Run(_data, _templatePath);
    }
}

public static string RenderTemplate<T>(string templatePath, T data)
{
    Closure<T> closure = new Closure<T>(templatePath, data);   
    ExecuteRazorMethod(closure);

    return closure.Result;
}

private static void ExecuteRazorMethod<T>(Closure<T> closure)
{
    try
    {
        closure.DelegateMethod();
    }
   .
   .
   .//irrelevant code
   .
}
dcastro
  • 59,520
  • 20
  • 126
  • 147
  • Thanks. Although I understand what happens better now, I still don't get how the 'data' which consist of some JSON , is able to generate some html code that it then stores in the result variable. Where would this be defined? – Force444 Aug 11 '14 at 10:28
  • @D.Singh I'm not sure I understood your question, but it seems to me that the `Razon.Run` method is the one responsible for generating that data. – dcastro Aug 11 '14 at 10:29
  • Ok, what I mean is, when Razor.Run method executes right? Then there is some code that takes 'data' and generates some html that is then stored in Result. Where would I find the code that is responsible for generating the html? In other words what code does Razor.Run execute? – Force444 Aug 11 '14 at 10:34
  • @D.Singh You want to take a look at the source code behind `Razor.Run`. The `Razor` class seems to be part of the [`RazorEngine` project](https://github.com/Antaris/RazorEngine). Here's the source code for that class: https://github.com/Antaris/RazorEngine/blob/master/src/Core/RazorEngine.Core/Razor.cs – dcastro Aug 11 '14 at 10:39
  • Ah okay! Reading the source code behind Razor.Run, helped me understand that this generation is in fact something that happens dynamically and is specifically used in generating templates. All makes sense now. Thanks for the link – Force444 Aug 11 '14 at 10:57
2

The compiler actually creates a named method from the

{ result = Razor.Run(data, templatePath); }

part. That is the Void <RenderTemplate> b__5 method. Remember anonymous types and methods are compiler magic (or syntactic sugar if you prefer), i.e. a C# feature, not a CLR feature. The compiler has to translate them into something the CLR understands.

When the delegate is created, it captures the data and templatePath variables, so it can access them when it's executed. That part is commonly known as closure.

bstenzel
  • 1,221
  • 9
  • 13
  • When the compiler creates that method, how does it know what to do in it? The effect of Razor.Run(data, templatePath) ends up storing html representing what's in the 'data' variable, in the result variable. I don't get where that generation happens. – Force444 Aug 11 '14 at 10:20
  • 1
    As @dcastro noted that part is happening inside the RazorEngine library. It's not affected/related by _how_ the code gets executed. – bstenzel Aug 11 '14 at 10:46