6

我想使用如下方法调用格式化任何数字类型:

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 等效于 C# 'dynamic' with Option Strict OnVB.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;
    }
}

C# 中的动态方法调用有效

那么给了什么?VB中有没有办法在不使用反射的情况下对函数的参数动态调用方法?

4

3 回答 3

4

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

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

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

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

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

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

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


细节

您的问题是Object.ToString()存在的,因此您的代码没有尝试任何动态调度,而是对该调用结果的默认String.Chars属性进行数组索引查找。Stringvalue.ToString()

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

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

在编译时。

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

于 2014-02-11T01:11:04.647 回答
0

您使用了很多隐式类型,编译器似乎没有将类型分配给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
于 2013-07-23T23:43:08.483 回答
0
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
于 2018-08-16T06:58:29.713 回答