VB.NET的Razor页面中的@@ <text>标记问题

时间:2019-01-11 22:08:07

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

我正在更新旧的VB.Net Aspnet MVC(剃刀页面)网站。更新.NET Framework版本,实体框架,MVC。

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

但是在这种情况下,在VB.NET中,它返回一个带对象的Anonymous方法,并返回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上搜索Google标志并没有产生任何有意义的答案,我仍然不知道那是什么。

现在,我正在更新的网站由于生成的代码无法编译而失败,并且生成的代码来自那些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:预期语句结束。

你知道@@是什么吗?知道这相当于C#吗?甚至有建议让我的Razor页面生成实际可编译的代码?

2 个答案:

答案 0 :(得分:2)

有问题的功能称为模板化的Razor委托内联Razor模板,它们在VB中生成Func<T, TResult>(或Func(Of T, TResult))。 NET,另请参见What is Func, how and when is it used),并允许插入@<tag>...</tag>格式的代码段。

创建模板化的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 ,该功能可为非相同参数为委托分配函数(包括lambda)(即使使用匿名委托也是如此),但仅在Option Strict设置关闭的情况下可用。如果在Razor视图上使用上述表达式添加@Option Strict On,则会看到此错误:

  

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

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

此功能在C#中不存在,必须使用带有Func<T, TResult>的显式转换才能从类型为TResult的lambda创建实例:

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

如果直接使用var result = (@<text>@myString</text>);,则会发生此异常,因为编译器不知道是否应将其转换为委托:

  

无法将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 WindowBuilder中的Content()方法重载之一包含Func<object, object>委托类型作为参数:

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<T, object>

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

答案 1 :(得分:1)

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

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>;
}