【问题标题】:VB.NET's @@<text> tags in Razor pages issuesRazor 页面中的 VB.NET 的 @@<text> 标记问题
【发布时间】:2019-06-06 20:35:17
【问题描述】:

我正在更新旧的 VB.Net Aspnet MVC(剃须刀页面)网站。正在更新 .NET Framework 版本、Entity Framework、MVC。

到目前为止,它工作得很好,除了几个使用@@ 运算符的页面。我以前看到过,为了逃避 Razor 的 @,在 C# 中。

但是在这种情况下,在 VB.NET 中,它返回一个匿名方法,该方法接受一个对象并返回一个 System.Web.WebPages.HelperResult。

以下代码:

@Code
    Dim myString As String
    myString = "mystring"
End Code

Double-At : @String.Format("{0}", @@<text>@myString</text>)
<br />
Double-At execution : @String.Format("{0}", (@@<text>Some @myString and then some</text>)(Nothing))
<br />

输出:

Double-At : VB$AnonymousDelegate_0`2[System.Object,System.Web.WebPages.HelperResult] 
Double-At execution : Somesome mystring and then some 

由于我不太习惯 VB.Net,因此我尝试在 C# 中找到等效的东西,以便我可以玩弄它并更好地理解它,但找不到类似的东西。

在标志处搜索 VB.Net Razor Double 并没有得到任何有意义的答案,我仍然不知道那是什么。

现在,我正在更新的网站因生成的代码无法编译而失败,并且生成的代码来自那些 Double At-Signs 函数。

作为参考,如果有人有想法,生成的代码无法编译,它会失败,因为我在 @@ 中使用的 @ 被拆分为多行,即使它们是一条指令。

例如:

@(Html.Kendo().Window() _
                    .Name("SomeWindow") _
                    .Draggable() _
                    .Modal(True) _
                    .Title("") _
                    .Width(300) _
                    .Content(@@<text>
    SomeValue : @LocalizedResources.SomeValue
</text>))

使用以下代码在运行时编译(点击页面时)崩溃:

WriteTo(__razor_template_writer, 

        #ExternalSource("C:\TestProject\TestPage.vbhtml",141)


        #End ExternalSource

        ##ExternalSource("C:\TestProject\TestPage.vbhtml",141)
             LocalizedResources.SomeValue)


        #End ExternalSource

WriteTo 函数的第二个参数出现在另一行的事实使编译器吐出一个错误,BC30205 : End of statement expected。

知道@@ 是什么吗?知道它的 C# 等价物是什么吗?甚至建议让我的 Razor 页面生成实际编译的代码?

【问题讨论】:

  • 不错的文章。很好的研究。
  • 哇,这是两个很棒的回应!作为参考,现在我了解了它的工作原理,并且我有点看到 Kendo mvc 是...... Kendo UI 的一个不必要的包装器,我将所有 Kendo MVC 调用重写为直接的 Javascript kendo 调用。在 Visual Studio 中玩得更好,这样我就避免了使用有问题的模板化 Razor 委托。仍然对为什么它最终会在运行时生成损坏的 VB.Net 代码感到困惑,而它在 .net 4.0 / mvc 3 / razor 1 上正常工作......但最后,这并不重要,因为我更喜欢少Kendo UI 与 Kendo Mvc 的复杂语法。

标签: c# asp.net-mvc vb.net razor


【解决方案1】:

所提及的功能称为 templated Razor delegateinline Razor 模板,它们会生成 Func&lt;T, TResult&gt;(或 VB.NET 中的 Func(Of T, TResult),另请参阅What is Func, how and when is it used) 并允许插入带有@&lt;tag&gt;...&lt;/tag&gt; 格式的sn-p。

创建模板化 Razor 委托的常用方法使用如下语法:

C#

@{
    string myString = "mystring";
    Func<object, HelperResult> helper = @<text>@myString</text>;
}

@String.Format("{0}", helper(myString))

VB.NET

@Code
    Dim myString As String = "mystring"
    Dim helper = (@@<text>@myString</text>)
@End Code

@String.Format("{0}", helper(myString))

VB.NET 定义实际上有这样的 lambda 表达式(通过应用GetType() 方法,我们可以知道 lambda 背后的底层类型):

Dim helper = Function(o As Object) 
    @<text>@myString</text>
End Function

C# 和 VB.NET 委托实现之间的区别在于 VB.NET 默认使用 relaxed delegate conversion,这使得能够将函数(包括 lambdas)分配给不同参数的委托(即使使用匿名委托),但仅在 Option Strict 设置关闭时可用。如果您在 Razor 视图中添加 @Option Strict On 并使用上述表达式,您将看到此错误:

Option Strict On 要求每个 lambda 表达式参数 如果无法推断其类型,则使用“As”子句声明。

简而言之,您不能将匿名委托与Option Strict On 一起使用,而是强制使用Func(Of Object, HelperResult)

此功能在 C# 中不存在,必须使用 Func&lt;T, TResult&gt; 的显式转换才能从 TResult 类型的 lambda 创建实例:

var result = (Func<object, HelperResult>)(@<text>@myString</text>);

如果直接使用var result = (@&lt;text&gt;@myString&lt;/text&gt;);会出现这个异常,因为编译器不知道是否应该转换为delegate:

无法将 lambda 表达式分配给隐式类型的局部变量

因此,同样的规则也适用于String.Format() 方法,它包含object 作为第二个参数:

// Error: cannot convert lambda expression to type 'object' because it is not a delegate type
@String.Format("{0}", ((@<text>@myString</text>)))
@String.Format("{0}", ((@<text>@myString</text>))(null))

// Correct
@String.Format("{0}", ((Func<object, HelperResult>)(@<text>@myString</text>)))
@String.Format("{0}", ((Func<object, HelperResult>)(@<text>@myString</text>))(null))

关于 Kendo 助手问题,Kendo UI 中的 Content() 方法重载之一 WindowBuilder 包含 Func&lt;object, object&gt; 委托类型作为参数:

namespace Kendo.Mvc.UI.Fluent
{
    public class WindowBuilder : WidgetBuilderBase<Window, WindowBuilder>, IHideObjectMembers
    {
        // other methods

        public WindowBuilder Content(Func<object, object> value)
        {
            base.Component.Template.InlineTemplate = value; // this is the inline template
            return this;
        }

        // other methods
    }
}

其中InlineTemplate 属性声明为Func&lt;T, object&gt;

public Func<T, object> InlineTemplate
{
    get
    {
        return this.inlineTemplate;
    }
    set
    {
        this.inlineTemplate = value;
        this.binder = delegate(T dataItem, IHtmlNode node)
        {
            // skipped for brevity 
        };
    }
}

因此,您可以在 CSHTML 页面中将 lambda 表达式作为参数传递:

@(Html.Kendo().Window()
              .Name("SomeWindow")
              .Draggable()
              .Modal(true)
              .Title("")
              .Width(300)
              .Content(@<text>SomeValue : @LocalizedResources.SomeValue</text>))

注意事项:

1) VB$AnonymousDelegateFunc(Of T, TResult) 不是同一类型。

2) 任何接受模板化 Razor 委托的助手都必须将TResult 参数定义为HelperResult,因此带有内联模板的@@ 指的是Func(Of T, HelperResult)

参考:

Templated Razor delegates

【讨论】:

    【解决方案2】:

    我认为可能需要 double-@,因为没有它,VB 会认为它是一个内联 XML 文档,但事实并非如此。无论如何,VB Razor 中的 @@&lt;text&gt;...&lt;/text&gt; 与 C# Razor 中的 @&lt;text&gt;...&lt;/text&gt; 相同。

    VB 版本正在创建一个匿名委托类型并将 lambda 转换为该类型,这样您就不必自己编写 DirectCast 表达式。另一方面,C# 不会创建匿名委托类型,因此它需要显式转换才能调用 lambda。

    等效的 CSHTML 是这样的(我会重复使用您的文本标签,以免引入噪音):

    Double-At : @String.Format("{0}", (Func<object,HelperResult>)(@<text>@myString</text>))
    <br />
    Double-At execution : @String.Format("{0}", ((Func<object,HelperResult>)(@<text>@myString</text>))(null))
    

    另一方面,将 lambda 分配给兼容类型的变量将隐式转换。你可以像这样重构它:

    @{
        Func<object, HelperResult> func = @<text>@myString</text>;
    }
    
    Double-At execution : @string.Format("{0}", func(null))
    

    然后您可以更进一步,通过使用 object 参数使其可重用。例如,如果将此类函数作为网格组件的列模板传递,则该行的数据项将在 object 参数中传递并称为 item

    @{
        Func<object, HelperResult> func = @<text>@item</text>;
    }
    
    Double-At execution(1) : @string.Format("{0}", func(myString))
    <br />
    Double-At execution(2) : @string.Format("{0}", func(myOtherString))
    

    至于 Kendo 组件,VB 肯定会拒绝多行内容,但 C# 不会。只需 un-double @,它在 C# 中应该没问题。例如,我在 VB 中无法做到这一点,但在 C# 中却完美运行:

    @{
        Func<object, HelperResult> func = @<text>
    ...
    @item
    ...
    </text>;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-09-18
      • 2022-06-13
      • 2021-10-02
      • 1970-01-01
      • 2021-12-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多