Dynamic call method in VB without reflection

I want to format any numeric type with a method call as follows:

Option Infer On Option Strict Off Imports System.Runtime.CompilerServices Namespace GPR Module GPRExtensions <Extension()> Public Function ToGPRFormattedString(value) As String ' Use VB 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 

Now, from various discussions on the Internet (the equivalent of VB.Net for C # 'dynamic' with the Strict On option , the Dynamic keyword equivalent in VB.Net? ), I would have thought that this code would work when passing a numeric type (double, Decimal , int, etc.). This is not as you can see in the screenshot:

Exception showing dynamic method call failing

I can explicitly convert the argument to double, and then .ToString("N3") works, but I simply cannot call it on the supposedly dynamic value argument.

However, I can do this in C # with the following code (using LINQPad). (Note: the compiler will not allow you to use the dynamic parameter in the extension method, so this may be part of the problem.)

 void Main() { Console.WriteLine (1.ToGPRFormattedString()); } internal static class GPRExtensions { public static string ToGPRFormattedString(this object o) { // Use VB 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; } } 

Dynamic method invocation in C # works

So what gives? Is there a way in VB to dynamically call a method by function argument without using reflection?

+5
dynamic
Jul 23 '13 at 20:03
source share
2 answers

To explicitly answer, "Is there a way in VB to dynamically call a method for a function argument without using reflection?":

EDIT: Now I looked at IL disassemblies (via LinqPad) and compared it to CallByName code (via Reflector), and using CallByName uses the usual amount of Reflection , Option Strict Off late binding.

So, the full answer: you can do this with Option Strict Off for all Object references, except when the method you are trying to exist on the Object itself, where you can use CallByName to get the same effect (and, on in fact, this does not need Option Strict Off ).

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

NB This is not actually the equivalent of the last call to the binding, which should take into account the possibility that the β€œmethod” is actually a (indexed) property, so it actually calls the equivalent:

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

for other methods like Double.CompareTo .




More details

Your problem is that Object.ToString() exists, so your code is not trying to dynamically dispatch, but is looking for the default index index for the String.Chars default property String from this call to value.ToString() .

You can confirm that this happens at compile time by trying value.ToString(1,2) , which you would prefer to perform a run-time search for the two ToString parameters, but it actually fails with

Too many arguments in the 'Public ReadOnly Default Chars property (As Integer index) Like Char'

at compile time.

Similarly, you can confirm that all other non- Shared Object methods are called directly using callvirt , relying on Overrides where possible, rather than dynamically sending calls to the Microsoft.VisualBasic.CompilerServices.NewLateBinding namespace if you look at the compiled code in IL .

+3
Feb 11 '14 at 1:11
source share

You use a lot of implicit text input, and the compiler does not seem to assign the System.Dynamic type to the variables you want to be dynamic.

You can try something like:

 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 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 
0
Jul 23 '13 at 23:43 on
source share



All Articles