如何将 lambda 传递给 Razor 辅助方法?

Posted

技术标签:

【中文标题】如何将 lambda 传递给 Razor 辅助方法?【英文标题】:How to pass in a lambda to a Razor helper method? 【发布时间】:2012-12-28 23:52:33 【问题描述】:

我有一个剃须刀辅助方法,它需要接受Func<>,它将返回一些要打印的 html 内容。这是我最初拥有的:

@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>);
              ))

不幸的是,我的文字永远不会被打印出来。也没有错误。

于是学习了inline helpers,把调用方式改成这样:

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

但是现在我得到一个编译错误说

“委托‘System.Func’不 接受 1 个参数”。

但我没有传递任何参数。

因此,如果我将其更改为 Func&lt;object,HelperResult&gt;,然后使用 @descriptions(null) 调用它,我会收到以下错误:

"不能使用 lambda 表达式作为动态的参数 在没有先将其强制转换给委托人的情况下分派操作或 表达式树类型"

我确定我在某处有问题,但我不确定是什么。

编辑:我想我可能已经解决了这个问题,但它引入了一些其他问题。

我所做的是在传递给动态方法之前强制转换 lambda。我想这就是错误想说的:

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

这行得通,它可以正确打印出span 标签。不幸的是,在调用Func 时,我必须传入一个无用的参数。

现在我遇到的问题是,我的真正功能不仅仅是编写一些跨度。更像是这样的:

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

@Helpers.Format 是另一个助手,资源是页面模型中的(动态)变量。

当然现在代码运行了,但没有打印出来(在&lt;span&gt; 标签内)。我在我的Format 辅助函数中放置了一个断点,它会命中它并且所有参数都已正确设置,所以我不确定它为什么不能正确输出。同样,如果我将其更改为 资源.描述 那么仍然没有任何输出。

由于它在此上下文之外运行良好,我想知道 Razor 的内联帮助程序不会捕获外部变量吗?

【问题讨论】:

【参考方案1】:

实际上,HelperResult 是 Microsoft 不希望您使用的东西,文档证明了这一点:

公共类 HelperResult:命名空间中的 IHtmlString System.Web.WebPages

总结:此类型/成员支持 .NET Framework 基础结构 并且不打算直接从您的代码中使用。

解决您的问题的一个可能方法是将您的描述函数包装在另一个助手中,然后将该助手作为 method group 传递给您的节点助手,如下所示:

@helper Node(string title, Func<HelperResult> descriptions)

    <div>@descriptions()</div>


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


@Node("title", Description)

在任何情况下,您的第一个想法都不应该奏效,因为 Func 类型的参数实际上等于无参数函数,在这种情况下,您需要像这样编写 lambda 表达式:

myFunction( () => doSomething)

所以你的函数调用应该是:

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

由于这些助手的未来是a bit dubious,我会考虑切换到HtmlHelpers 用于html 的小sn-ps 或Partials 用于更大的块。

【讨论】:

最好不要让 HelperResult 的未来“可疑”!我们在公司的流体引导库中广泛使用了 HelperResult(等待更完善,直到我们在 github 上分享它)。当他们说:“并且不打算直接从您的代码中使用”时,这并不意味着他们正在拉动对它的支持,只是它不会经常出现在您的代码中。但是许多/大多数 MVC 工具集/较低级别的库都依赖于这些东西。 “这些帮手的未来有点可疑” - 有人在那个链接中说什么?谢天谢地,我没看到。干杯。 例如,这允许我们将 Razor 代码直接添加到库中强大而美观: --- public void Add(Func html) Add(html.ToString()) ; --- 用户永远不会看到这些函数,他们只是知道可以在链中调用 somecontrol.Add(@howdy)) --- 用例是适合流体类型库。 @NicholasPetersen 一个主要的商业图书馆,Kendo Grid,使用这些 AFAIK,.Template(@&lt;text&gt;@item.Blah&lt;text&gt;),如果这能让你放心的话。你有关于这些的任何好的文档吗,“MVC 内联模板”和变体出现了很多不相关的文章。它们看起来确实很强大,我想自己更多地使用它们。 感谢亚伦的信息!是的,这让我很放心。我不知道我是否理解您关于“mvc 内联模板”的问题,您是指 Kendo 是如何使用这些模板的吗?但不知道,任何给定的控件,您都可以允许用户使用这种技术自定义输出的某些部分(允许将剃须刀代码传递到其中),这将是有意义的。 我参加聚会有点晚了,但我只想指出我说的是@helper 语法,而不是 HelperResult 类,尽管它们可能密切相关。我引用了从事 ASP.NET MVC 的“marcind”:>就像你说的那样,我怀疑微软会突然删除它,因为知道有很多库在使用它。【参考方案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);
    

【讨论】:

以上是关于如何将 lambda 传递给 Razor 辅助方法?的主要内容,如果未能解决你的问题,请参考以下文章

将js变量或输入值传递给razor

如何将值传递给 CloudWatch 中的 Lambda 函数?

如何将两个模型组合成一个模型并使用 asp.net MVC razor 将其传递给查看

如何将测试夹具传递给 C++ GTest 中的辅助函数

将数据从 javascript 传递到 asp.net core 2 razor 页面方法

如何将值从javascript变量传递给剃刀变量?