【问题标题】:VB.NET equivalent for C# 'dynamic' with Option Strict On带有 Option Strict On 的 C#“动态”的 VB.NET 等效项
【发布时间】:2011-02-22 19:34:35
【问题描述】:

在使用类型安全的 VB.NET 时,C# 4 'dynamic' 关键字是否有等效项,即使用Option Strict On

【问题讨论】:

  • VB 是类型安全的,无论 Option Strict 是 On 还是 Off。在这里阅读含义msdn.microsoft.com/en-us/library/hbzz1a9a(VS.80).aspx
  • @jdk 好的,我想我必须同意。然而,我的意思是编译时检查类型安全,你可能已经猜到了......
  • @jdk:大家谈及编程语言时使用的类型安全的定义是这样的:en.wikipedia.org/wiki/Type_safety
  • @jeroenh 我受到启发,在 Microsoft Connect 上发布了一个建议,如果 VB 在 C# 中有类似 dynamic 的东西会很好。任何同意或不同意的人都可以投票或评论Microsoft Connect here
  • Microsoft VB 规范负责人有just blogged about this idea。 VB 团队的临时评估是“VB 一直有自己的通过 Object 进行后期绑定的形式。虽然遗憾的是您不能将后期绑定的范围限定为小于文件粒度,但这似乎不是一个足够大的问题证明第二种形式的后期绑定是合理的。”亲爱的读者,如果您对此有强烈的感觉,为什么不在博客上发表评论,或者对我之前评论中提到的 Microsoft Connect 问题发表评论。

标签: c# vb.net dynamic option-strict


【解决方案1】:

等效的是 VB.NET 中的 Object,但带有 Option Strict Off。使用 Option Strict On 没有等价物。换句话说,dynamic 关键字为 C# 带来了 Option Strict Off 等效功能。

【讨论】:

  • 除了不完全一样。例如,我不知道如何像在 C# 中那样动态调用方法(参见 stackoverflow.com/questions/17819977/…)。
  • 更重要的是,C# 模型允许您为特定对象创建异常,而 VB 模型则强制您执行的粒度要小得多
  • 我知道这是一个老问题,但有一种方法可以进行后期绑定并保持 Option Strict。在项目属性的 Compile 选项卡中,我们可以将 Late Binding 设置为“None”(并且 Option Strict 采用“Custom”状态),允许在比将其设置为 Off 更安全的环境中进行 Late Binding
  • 您只需调用对象就可以动态调用 vb.net 中的方法。当然,请确保包括括号。
  • CallByName - 应该可以帮助任何网络搜索者:docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/…
【解决方案2】:

您可以打开 Option Infer On 和 Option Strict Off 仍然有一些非常接近的东西。

【讨论】:

    【解决方案3】:

    VB.NET 始终具有内置的“动态”功能,最初称为后期绑定。永远支持此语法:

     Dim obj = new SomeComClass()
     obj.DoSomething()
    

    处理在 .NET 和 COM 中实现的代码,后者是最常见的用途。 C# 中的 dynamic 关键字赋予了它相同的功能。它在 VB.NET 版本 10 中确实发生了变化,但它现在也使用 DLR。这增加了对 Python 和 Ruby 等语言实现的动态绑定的支持。

    语法完全一样,使用 Dim 关键字不带 As。但是,您将不得不使用Option Strict OffOption Infer On 可以稍微减轻这种打击。它确实表明 C# 使用特定关键字来表示动态绑定是一个非常好的举措。 Afaik 所有在 VB.NET 中这样做的请求都已被考虑但尚未计划。

    如果您更喜欢Option Strict On,那么使用Partial Class 关键字可以将部分代码移动到另一个源文件中可能是最有效的方法。

    【讨论】:

    • @Hans Passant:我知道,但是 C# 动态与 VB 的“后期绑定”并不完全相同。在 C# 中,使用 dynamic 关键字,我可以非常明确地了解程序的动态部分。对我来说,这就像告诉编译器:“嘿,我知道我在为我的程序的这个特定部分做什么”。使用 VB.Net 我必须为我的整个项目关闭 Option Strict,这可能会导致一些细微的错误因此而蔓延。
    • @Hans @jeroen。在您编辑的代码中,app 被推断为类型Object,因此无法使用 Excel 应用程序对象app。例如,如果我用app.Calculate 替换你有REM etc... 它不会编译。我认为这是 jeroen 所问的问题。编译器说Error 1 Option Strict On disallows late binding.
    • @MarkJ - 你是绝对正确的。我检查了 VB.NET 版本 10 语言规范以确定。令人震惊的是,任何地方都没有提到 DLR。 Option Strict Off 看起来完全不可避免。对于糟糕的答案,我深表歉意。
    • 我受到启发在 Microsoft Connect 上发布了一条建议,即 VB 应该有类似 dynamic 的内容。任何强烈同意或不同意的人都可以投票或评论Microsoft Connect here
    • @jeroenh 您可以在文件顶部使用不同的Option 指令覆盖文件级别的项目级别选项。
    【解决方案4】:

    有足够的方法来处理具有后期绑定 COM 对象和类型安全的方法和属性 (Option Strict On)。这在使用 Microsoft.VisualBasic.Interaction.CallByName 和 System.Type.InvokeMember 方法时。 (或者创建一个单独的“部分”文件,其中Option StrictOff)。

    但是在 VB.NET 中使用后期绑定处理事件并不像在 C# 中使用动态类型那样简单。您可以在 Dynamic Events in VB.NET 中查看“hack”。

    【讨论】:

      【解决方案5】:

      这将证明 Basic 所说的 VB 在这方面的粒度与 C# 不同。我在 C# 中有这段代码,它使用反射在运行时动态调用方法:

      var listResult = tgtObj.GetType().GetMethod("GetSomeData").Invoke(tgtObj, null);
      

      我这样做的原因是“GetSomeData”可以是多种方法中的任何一种,每种方法获取不同的数据。此处调用哪个方法取决于在运行时传递给该对象的字符串参数,因此“GetSomeData”的值在运行时会有所不同。

      “GetSomeData”的签名是:

      public List<SomeResultSetClass> GetSomeData()
      

      每个调用的方法都返回某种List&lt;T&gt; 对象。接下来,我将 listResult 对象发送到名为 Export 的通用方法,如下所示:

      void Export<T>(List<T> exportList, string filePath, byte fileType) where T: class;
      

      这是我们遇到问题的地方。 Invoke 返回一个 System.Object 类型的对象。当然一个List&lt;T&gt;也是一个System.Object,但是暴露出来的接口是System.Object接口,而不是IList接口。如果我尝试执行 Export 方法,则:

      myExportObj.Export(listResult, parms.filePath, parms.fileType);
      

      代码编译失败。错误是:

      The type arguments for method '...Export&lt;T&gt;...' cannot be inferred from the usage. Try specifying the type arguments explicitly.

      不,谢谢!!问题是编译器找不到 IList 元数据,因为它正在查看 System.Object 接口。现在,您可以创建一个新的List&lt;T&gt;,将(List&lt;Whatever&gt;) 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 中,我必须关闭包含该行的整个模块的类型检查器。没有比这更细的粒度了。

      【讨论】:

        【解决方案6】:

        是的,ExpandoObject。

        Dim DObj = 新 System.Dynamic.ExpandoObject()

        DObj.A = "abc"

        DObj.B = 123

        【讨论】:

        • ExpandoObject 似乎在后台使用了 IDictionary(Of string, object)。很有趣。
        • 问题询问如何使用Option Strict On。您的回答仅适用于Option Strict Off
        【解决方案7】:

        请注意,即使启用了 Option Strict,您仍然可以使用例如一个 ExpandoObject 来访问如下属性:

        Dim doc = JsonConvert.DeserializeObject(Of ExpandoObject)("{""name"":""Bob""}")
        Dim lookup as IDictionary(Of String, Object) = doc
        lookup("name") ' Bob
        

        【讨论】:

          【解决方案8】:

          Vb.Net 中带有选项 strict on 的 c# 动态关键字的等效项以 NuGet 包的形式存在:Dynamitey。

          安装包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 测试。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多