使用类型安全的 VB.NET 时,C# 4 'dynamic' 关键字是否有等效项,即 with Option Strict On
?
8 回答
等效的是 VB.NET 中的 Object 但带有Option Strict Off
. Option Strict On
没有等价物。换句话说,动态关键字为Option Strict Off
C# 带来了等效的功能。
VB.NET 始终具有内置的“动态”功能,最初称为后期绑定。永远支持此语法:
Dim obj = new SomeComClass()
obj.DoSomething()
处理在 .NET 和 COM 中实现的代码,后者是最常见的用途。C# 中的dynamic关键字赋予了它同样的能力。它在 VB.NET 版本 10 中确实发生了变化,但它现在也使用 DLR。这增加了对 Python 和 Ruby 等语言实现的动态绑定的支持。
语法完全一样,使用不带 As 的 Dim 关键字。但是,您将不得不使用Option Strict Off
,Option Infer On
可以稍微减轻这种打击。它确实表明 C# 使用特定关键字来表示动态绑定是一个非常好的举措。Afaik 所有在 VB.NET 中这样做的请求都已被考虑但尚未计划。
如果您愿意Option Strict On
,那么使用Partial Class
关键字将一些代码移动到另一个源文件中可能是最有效的方法。
这将证明 Basic 所说的 VB 在这方面的粒度与 C# 不同。我在 C# 中有这段代码,它使用反射在运行时动态调用方法:
var listResult = tgtObj.GetType().GetMethod("GetSomeData").Invoke(tgtObj, null);
我这样做的原因是“GetSomeData”可以是多种方法中的任何一种,每种方法都获取不同的数据。此处调用哪个方法取决于在运行时传递给该对象的字符串参数,因此“GetSomeData”的值在运行时会有所不同。
“GetSomeData”的签名是:
public List<SomeResultSetClass> GetSomeData()
调用的每个方法都返回某种List<T>
对象。接下来,我将 listResult 对象发送到名为 Export 的通用方法,如下所示:
void Export<T>(List<T> exportList, string filePath, byte fileType) where T: class;
这是我们遇到问题的地方。Invoke 返回一个 System.Object 类型的对象。当然aList<T>
也是System.Object,但是暴露出来的接口是System.Object接口,而不是IList接口。如果我尝试执行 Export 方法,则:
myExportObj.Export(listResult, parms.filePath, parms.fileType);
代码无法编译。错误是:
The type arguments for method '...Export<T>...' cannot be inferred from the usage. Try specifying the type arguments explicitly.
不,谢谢!!问题是编译器找不到 IList 元数据,因为它正在查看 System.Object 接口。现在,您可以创建一个新的List<T>
,分配(List<Whatever>) listResult
给它,但这首先违背了动态调用的目的。
解决方法是更改var
为dynamic
:
dynamic listResult = tgtObj.GetType().GetMethod("GetSomeData").Invoke(tgtObj, null);
由于动态在编译时绕过了静态类型检查,因此我们不会收到编译错误。然后,当动态对象被传递给 Export 方法时,DLR(动态语言运行时)查看它是否可以隐式转换对象以满足方法签名的要求。当然可以。
好的,这就是 C# 中的工作方式。使用 VB,该行如下所示:
Dim listResult = tgtObj.GetType().GetMethod("GetSomeData").Invoke(tgtObj, Nothing)
使用 Option Strict On 时,这一行会扰乱编译器,正如预期的那样。关闭它,它工作正常。换句话说,在 VB 中,我必须关闭包含该行的整个模块的类型检查器。没有比这更精细的粒度了。
您可以打开 Option Infer On 和 Option Strict Off 并且仍然有一些非常接近的东西。
有足够的方法来处理具有后期绑定 COM 对象和类型安全 ( Option Strict On
) 的方法和属性。这在使用 Microsoft.VisualBasic.Interaction.CallByName 和 System.Type.InvokeMember 方法时。(或创建一个单独的“部分”文件,其中Option Strict
is Off
)。
但是使用 VB.NET 的后期绑定来处理事件并不像使用 C# 中的动态类型那样简单。您可以在 VB.NET 的动态事件中检查“hack” 。
Vb.Net 中带有选项 strict 的 c# 动态关键字的等效项以 NuGet 包的形式存在:Dynamitey。
install-package Dynamitey 之后,可以编写如下 Vb.Net 代码:
Option Strict On : Option Infer On : Option Explicit On
Imports Dynamitey
Module Module1
Public Sub Main()
Dim o = Nothing
o = "1234567890"
Console.WriteLine(Dynamic.InvokeMember(o, "Substring", 5)) ' writes 67890
End Sub
End Module
或者更具可读性:
Option Strict On : Option Infer On : Option Explicit On
Imports Dynamitey
Module Module1
<Extension()>
Public Function Substring(self As Object, offset As Integer) As String
Return CType(Dynamic.InvokeMember(self, "Substring", offset), String)
End Function
Public Sub Main()
Dim o = Nothing
o = "1234567890"
Console.WriteLine(Substring(o, 5)) ' writes 67890
End Sub
End Module
使用 VS2017 和 .net Framework 4.7.2 测试。
是的,ExpandoObject。
暗 DObj = 新 System.Dynamic.ExpandoObject()
DObj.A = "abc"
DObj.B = 123
请注意,即使使用 Option Strict,您仍然可以使用例如 ExpandoObject 来访问以下属性:
Dim doc = JsonConvert.DeserializeObject(Of ExpandoObject)("{""name"":""Bob""}")
Dim lookup as IDictionary(Of String, Object) = doc
lookup("name") ' Bob