【问题标题】:Dynamic method calling in VB without reflectionVB中的动态方法调用没有反射
【发布时间】:2013-07-23 02:24:51
【问题描述】:

我想使用这样的方法调用来格式化任何数字类型:

Option Infer On
Option Strict Off
Imports System.Runtime.CompilerServices

Namespace GPR
    Module GPRExtensions
        <Extension()>
        Public Function ToGPRFormattedString(value) As String
            ' Use VB's dynamic dispatch to assume that value is numeric
            Dim d As Double = CDbl(value)
            Dim s = d.ToString("N3")
            Dim dynamicValue = value.ToString("N3")
            Return dynamicValue
        End Function
    End Module
End Namespace

现在,根据网络上的各种讨论(VB.Net equivalent for C# 'dynamic' with Option Strict OnDynamic Keyword equivalent in VB.Net?),我认为此代码在传递数字类型(double、Decimal、int 等)时会起作用。它没有,正如您在屏幕截图中看到的那样:

我可以将参数显式转换为双精度,然后 .ToString("N3") 工作,但只是在所谓的动态 value 参数上调用它失败。

但是,我可以使用以下代码在 C# 中执行此操作(使用 LINQPad)。 (注意,编译器不允许你在扩展方法中使用dynamic 参数,所以这可能是问题的一部分。)

void Main()
{
    Console.WriteLine (1.ToGPRFormattedString());
}

internal static class GPRExtensions
{
    public static string ToGPRFormattedString(this object o)
    {
        // Use VB's dynamic dispatch to assume that value is numeric
        var value = o as dynamic;
        double d = Convert.ToDouble(value);
        var s = d.ToString("N3").Dump("double tostring");
        var dynamicValue = value.ToString("N3");
        return dynamicValue;
    }
}

那是什么? VB中有没有一种方法可以在不使用反射的情况下对函数的参数动态调用方法?

【问题讨论】:

    标签: vb.net dynamic


    【解决方案1】:
    Option Infer On
    Option Strict Off
    Imports System.Runtime.CompilerServices
    
    Namespace GPR
        Module GPRExtensions
            <Extension()>
            Public Function ToGPRFormattedString(value) As String
                Dim dynamicValue = FormatNumber(CDbl(value), 3)
                Return dynamicValue
            End Function
        End Module
    End Namespace
    

    【讨论】:

      【解决方案2】:

      明确回答“在 VB 中有没有一种方法可以在不使用反射的情况下动态调用函数的参数?”:

      编辑:我现在查看了一些 IL 反汇编(通过 LinqPad)并将其与 CallByName 的代码(通过 Reflector)进行比较,使用 CallByName 使用与正常相同数量的 ReflectionOption Strict Off后期绑定。

      所以,完整的答案是:对于所有 Object 引用,您可以使用 Option Strict Off 执行此操作,除非您尝试的方法存在于 Object 本身,您可以使用 CallByName 获取相同的效果(事实上,不需要Option Strict Off)。

      Dim dynamicValue = CallByName(value, "ToString", CallType.Method, "N3")
      

      NB 这实际上并不等同于后期绑定调用,它必须满足“方法”实际上是一个(n 索引)属性的可能性,所以它实际上调用了等价于:

      Dim dynamicValue = CallByName(value, "ToString", CallType.Get, "N3")
      

      对于其他方法,例如Double.CompareTo


      详情

      您的问题是存在Object.ToString(),因此您的代码没有尝试任何动态调度,而是在String 调用的默认String.Chars 属性上查找数组索引。 /p>

      您可以通过尝试value.ToString(1,2) 来确认这是在编译时发生的情况,您更愿意尝试在运行时查找两个参数ToString,但实际上失败了

      'Public ReadOnly Default Property Chars(index As Integer) As Char' 的参数过多

      在编译时。

      您可以类似地确认所有其他非Shared Object 方法直接使用callvirt 调用,依赖于Overrides(如果可用),而不是调用Microsoft.VisualBasic.CompilerServices.NewLateBinding 命名空间的动态调度,如果您查看在 IL 中编译代码。

      【讨论】:

      • 我不太明白。我知道ToString 存在于Object 上——这就是为什么我不希望我的变量是Object 类型而是dynamic 类型。这在 C# 中是可能的,但在 VB 中似乎不起作用。
      • 是的,这就是你要表达的意思。然后我只是澄清为什么 VB 现有的 Object 概念为 dynamic 在这里对你不适用。
      【解决方案3】:

      您使用了很多隐式类型,编译器似乎没有将类型 System.Dynamic 分配给您想要动态的变量。

      你可以试试这样的:

      Option Infer On
      Option Strict Off
      Imports System.Runtime.CompilerServices
      
      Namespace GPR
          Module GPRExtensions
              <Extension()>
              Public Function ToGPRFormattedString(value as System.Dynamic) As String
                  ' Use VB's dynamic dispatch to assume that value is numeric
                  Dim d As Double = CDbl(value)
                  Dim s = d.ToString("N3")
                  Dim dynamicValue as System.Dynamic = value.ToString("N3")
                  Return dynamicValue
              End Function
          End Module
      End Namespace
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-02-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-08
        相关资源
        最近更新 更多