我正在更新旧的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页面生成实际可编译的代码?
答案 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$AnonymousDelegate
和Func(Of T, TResult)
的类型不同。
2)任何接受模板化的Razor委托的助手都必须将TResult
参数定义为HelperResult
,因此带有内联模板的@@
指向Func(Of T, HelperResult)
。
参考:
答案 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>;
}