How to pass in a lambda to a Razor helper method?

允我心安 提交于 2019-12-22 02:43:50

问题


I have a razor helper method that needs to take in a Func<> that will return some HTML content to print out. This is what I originally had:

@helper node(string title, Func<HelperResult> descriptions)
{
    ....
    <div>@descriptions()</div>
    ....
}

@node("title", 
              new Func<HelperResult>(() => 
              {
                 return new HelperResult(
                     @<text>
                     <span>"desc1"</span>
                     <span>"desc2"</span>
                     </text>);
              }))

Unfortunately with this my text never gets printed out. No error either.

So I learned about inline helpers, and changed the calling method to this:

@node("title",                     
              @<text>
              <span>"desc1"</span>
              <span>"desc2"</span>
              </text>)

However now I get a compilation error saying

"Delegate 'System.Func' does not take 1 arguments".

But I'm not passing in any arguments.

So if I change it to Func<object,HelperResult> and then call it using @descriptions(null) I get the following error:

"Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type"

I'm sure I have something wrong somewhere, but I'm not sure what it is.

Edit: I think I may have solved that problem but it introduces some other issues.

What I did was to cast the lambda before passing into a dynamic method. I guess that's what the error was trying to say:

@node("title",                     
              ((Func<dynamic, HelperResult>)(@<text>
              <span>"desc1"</span>
              <span>"desc2"</span>
              </text>))

That works and it prints out the span tags correctly. Unfortunately I have to pass in a useless parameter when calling this Func.

Now the issue I have is that my real function does a bit more than just write some spans. It's more like this:

@node("title",                     
              ((Func<dynamic, HelperResult>)(@<text>
              <span>@Helpers.Format(resource.Description,"item")</span>
              </text>))

Where @Helpers.Format is another helper and resource is a (dynamic) variable from the page model.

Of course now the code runs but nothing is printed out (inside the <span> tag). I put a breakpoint inside my Format helper function, and it hits it and all the parameters are correctly set, so I'm not sure why it wouldn't output correctly. Similarly if I just change it to resource.Description then nothing still gets output.

Since it works well outside of this context, I wonder does Razor's inline helpers not capture the outer variables?


回答1:


Actually HelperResult is something Microsoft would rather you didn't use, as evidenced by documentation:

public class HelperResult : IHtmlString in namespace System.Web.WebPages

Summary: This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.

A possible solution to your problem might be to wrap your description function in another helper and then pass that helper as a method group to your node helper, like this:

@helper Node(string title, Func<HelperResult> descriptions)
{
    <div>@descriptions()</div>
}

@helper Description() {
    <span>desc1</span>
    <span>desc2</span>
}

@Node("title", Description)

In any case, your first idea shouldn't work because a parameter of type Func is in fact equal to a parameterless function, in which case you need to write the lambda expression like this:

myFunction( () => doSomething)

So your function call would have been:

@node("title", () =>                    
              @<text>
              <span>"desc1"</span>
              <span>"desc2"</span>
              </text>)

Since the future of these helpers is a bit dubious though, I would consider switching to either HtmlHelpers for small snippets of html or Partials for larger chunks.




回答2:


@Test(new Func<object, HelperResult>[]{@<text>hello</text>})

@Test(new Func<object, HelperResult>[]{@<text>hello</text>,@<text>world</text>})


@helper Test(params Func<object, HelperResult>[] results)
{
    foreach (var result in results)   
    {
        @result(null);
    }
}


来源:https://stackoverflow.com/questions/14328303/how-to-pass-in-a-lambda-to-a-razor-helper-method

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!