dotnet / vblang

The home for design of the Visual Basic .NET programming language and runtime library.
288 stars 65 forks source link

ExpandoObject: Why must I use the Invoke method to call a dynamic function? #226

Open ghost opened 6 years ago

ghost commented 6 years ago

This sample will work fine:

Dim Test As Object = New ExpandoObject()
Test.Inc = Function(x As Integer) x + 1
Dim z = Test.Inc.Invok(2)

But in I erase the Invoke method from the last line: Dim z = Test.Inc(2) it will raise an exception. This doesn't happen in C#, where I can call the delegate without the Invoke method:

dynamic Test = new ExpandoObject();
Test.Inc = (Func<int,int>) ((int x) => x + 1);
var z = Test.Inc(2);

In fact , C# raise an exception when I use the Invoke method!

This is the VB.NET Exception details

System.MissingMemberException HResult=0x80131512 Message=No default member found for type 'VB$AnonymousDelegate_0(Of Integer,Integer)'. Source=Microsoft.VisualBasic StackTrace: at Microsoft.VisualBasic.CompilerServices.Symbols.Container.GetMembers(String& MemberName, Boolean ReportErrors) at Microsoft.VisualBasic.CompilerServices.NewLateBinding.CallMethod(Container BaseReference, String MethodName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack, BindingFlags InvocationFlags, Boolean ReportErrors, ResolutionFailure& Failure) at Microsoft.VisualBasic.CompilerServices.NewLateBinding.InternalLateIndexGet(Object Instance, Object[] Arguments, String[] ArgumentNames, Boolean ReportErrors, ResolutionFailure& Failure, Boolean[] CopyBack) at Microsoft.VisualBasic.CompilerServices.NewLateBinding.ObjectLateInvokeDefault(Object Instance, Object[] Arguments, String[] ArgumentNames, Boolean ReportErrors, Boolean[] CopyBack) at Microsoft.VisualBasic.CompilerServices.NewLateBinding.InternalLateInvokeDefault(Object Instance, Object[] Arguments, String[] ArgumentNames, Boolean ReportErrors, Boolean[] CopyBack) at Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateGetInvokeDefault(Object Instance, Object[] Arguments, String[] ArgumentNames, Boolean ReportErrors) at Microsoft.VisualBasic.CompilerServices.IDOUtils.CreateRefCallSiteAndInvoke(CallSiteBinder Action, Object Instance, Object[] Arguments) at Microsoft.VisualBasic.CompilerServices.IDOBinder.IDOGet(IDynamicMetaObjectProvider Instance, String MemberName, Object[] Arguments, String[] ArgumentNames, Boolean[] CopyBack) at Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateGet(Object Instance, Type Type, String MemberName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack) at WindowsApp6.Form1.Main() in C:\Users\mhg\Documents\Visual Studio 2017\Projects\WindowsApp6\WindowsApp6\Form1.vb:line 12 at WindowsApp6.Form1.Form1_Load(Object sender, EventArgs e) in C:\Users\mhg\Documents\Visual Studio 2017\Projects\WindowsApp6\WindowsApp6\Form1.vb:line 31 at System.EventHandler.Invoke(Object sender, EventArgs e) at System.Windows.Forms.Form.OnLoad(EventArgs e) at System.Windows.Forms.Form.OnCreateControl() at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible) at System.Windows.Forms.Control.CreateControl() at System.Windows.Forms.Control.WmShowWindow(Message& m) at System.Windows.Forms.Control.WndProc(Message& m) at System.Windows.Forms.ScrollableControl.WndProc(Message& m) at System.Windows.Forms.Form.WmShowWindow(Message& m) at System.Windows.Forms.Form.WndProc(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) at System.Windows.Forms.SafeNativeMethods.ShowWindow(HandleRef hWnd, Int32 nCmdShow) at System.Windows.Forms.Control.SetVisibleCore(Boolean value) at System.Windows.Forms.Form.SetVisibleCore(Boolean value) at System.Windows.Forms.Control.set_Visible(Boolean value) at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context) at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context) at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun() at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel() at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine) at WindowsApp6.My.MyApplication.Main(String[] Args) in :line 81

AnthonyDGreen commented 6 years ago

The late-binder just needs to be updated to use the same logic and we do for the early bound case where () can invoke a delegate. Today the late-binder only uses (arguments) for default property access or actual method invocation. I'll leave this issue open to reminder to fix this bug ASAP. Thanks!

ghost commented 6 years ago

@AnthonyDGreen Thanks.