File: Microsoft\VisualBasic\CompilerServices\NewLateBinding.vb
Web Access
Project: src\src\libraries\Microsoft.VisualBasic.Core\src\Microsoft.VisualBasic.Core.vbproj (Microsoft.VisualBasic.Core)
' Licensed to the .NET Foundation under one or more agreements.
' The .NET Foundation licenses this file to you under the MIT license.
 
Imports System
Imports System.Collections.Generic
Imports System.Diagnostics
Imports System.Dynamic
Imports System.Reflection
 
Imports Microsoft.VisualBasic.CompilerServices.Symbols
Imports Microsoft.VisualBasic.CompilerServices.OverloadResolution
Imports System.Diagnostics.CodeAnalysis
 
#Const NEW_BINDER = True
#Const BINDING_LOG = False
 
Namespace Microsoft.VisualBasic.CompilerServices
 
    ' Implements VB late binder.
    <ComponentModel.EditorBrowsable(ComponentModel.EditorBrowsableState.Never)>
    Public NotInheritable Class NewLateBinding
        Private Const LateBindingTrimMessage As String = "Late binding is dynamic and cannot be statically analyzed. The referenced types and members may be trimmed"
        ' Prevent creation.
        Private Sub New()
        End Sub
 
        <DebuggerHiddenAttribute()> <DebuggerStepThroughAttribute()>
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Public Shared Function LateCall(
                ByVal Instance As Object,
                ByVal Type As System.Type,
                ByVal MemberName As String,
                ByVal Arguments As Object(),
                ByVal ArgumentNames As String(),
                ByVal TypeArguments As System.Type(),
                ByVal CopyBack As Boolean(),
                ByVal IgnoreReturn As Boolean) As Object
 
            If Arguments Is Nothing Then Arguments = NoArguments
            If ArgumentNames Is Nothing Then ArgumentNames = NoArgumentNames
            If TypeArguments Is Nothing Then TypeArguments = NoTypeArguments
 
            Dim baseReference As Container
            If Type IsNot Nothing Then
                baseReference = New Container(Type)
            Else
                baseReference = New Container(Instance)
            End If
 
            If baseReference.IsCOMObject AndAlso Not baseReference.IsWindowsRuntimeObject Then
                Return LateBinding.InternalLateCall(Instance, Type, MemberName, Arguments, ArgumentNames, CopyBack, IgnoreReturn)
            End If
 
            Dim idmop As IDynamicMetaObjectProvider = IDOUtils.TryCastToIDMOP(Instance)
            If idmop IsNot Nothing AndAlso TypeArguments Is NoTypeArguments Then
                Return IDOBinder.IDOCall(idmop, MemberName, Arguments, ArgumentNames, CopyBack, IgnoreReturn)
            Else
                Return ObjectLateCall(Instance, Type, MemberName, Arguments,
                    ArgumentNames, TypeArguments, CopyBack, IgnoreReturn)
            End If
        End Function
 
        'This method is only called from DynamicMethods generated at runtime
        <Obsolete("FallbackCall has been deprecated and is not supported.", True)>
        <System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)>
        <DebuggerHiddenAttribute()> <DebuggerStepThroughAttribute()>
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Public Shared Function FallbackCall(
                ByVal Instance As Object,
                ByVal MemberName As String,
                ByVal Arguments As Object(),
                ByVal ArgumentNames As String(),
                ByVal IgnoreReturn As Boolean) As Object
 
            Return ObjectLateCall(Instance, Nothing, MemberName, Arguments,
                ArgumentNames, NoTypeArguments, IDOBinder.GetCopyBack(), IgnoreReturn)
        End Function
 
        <DebuggerHiddenAttribute()> <DebuggerStepThroughAttribute()>
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Private Shared Function ObjectLateCall(
                ByVal instance As Object,
                ByVal type As System.Type,
                ByVal memberName As String,
                ByVal arguments As Object(),
                ByVal argumentNames As String(),
                ByVal typeArguments As System.Type(),
                ByVal copyBack As Boolean(),
                ByVal ignoreReturn As Boolean) As Object
 
            Dim baseReference As Container
            If type IsNot Nothing Then
                baseReference = New Container(type)
            Else
                baseReference = New Container(instance)
            End If
 
            Dim invocationFlags As BindingFlags = BindingFlagsInvokeMethod Or BindingFlagsGetProperty
            If ignoreReturn Then invocationFlags = invocationFlags Or BindingFlagsIgnoreReturn
 
            Dim failure As ResolutionFailure
 
            Return CallMethod(
                       baseReference,
                       memberName,
                       arguments,
                       argumentNames,
                       typeArguments,
                       copyBack,
                       invocationFlags,
                       True,
                       failure)
        End Function
 
        'Quick check to determine if FallbackCall will succeed
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Friend Shared Function CanBindCall(ByVal instance As Object, ByVal memberName As String, ByVal arguments As Object(), ByVal argumentNames As String(), ByVal ignoreReturn As Boolean) As Boolean
            Dim baseReference As New Container(instance)
            Dim invocationFlags As BindingFlags = BindingFlagsInvokeMethod Or BindingFlagsGetProperty
            If ignoreReturn Then invocationFlags = invocationFlags Or BindingFlagsIgnoreReturn
 
            Dim failure As ResolutionFailure
            Dim members As MemberInfo() = baseReference.GetMembers(memberName, False)
            If members Is Nothing OrElse members.Length = 0 Then
                Return False
            End If
 
            Dim targetProcedure As Method =
                ResolveCall(
                    baseReference,
                    memberName,
                    members,
                    arguments,
                    argumentNames,
                    NoTypeArguments,
                    invocationFlags,
                    False,
                    failure)
 
            Return failure = ResolutionFailure.None
        End Function
 
        ' LateCallInvokeDefault is used to optionally invoke the default action on a call target.
        ' If the arguments are non-empty, then it isn't optional, and is treated
        ' as an error if there is no default action.
        ' Currently we can get here only in the process of execution of NewLateBinding.LateCall.
        <System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)>
        <DebuggerHiddenAttribute()> <DebuggerStepThroughAttribute()>
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Public Shared Function LateCallInvokeDefault(
                ByVal Instance As Object,
                ByVal Arguments As Object(),
                ByVal ArgumentNames As String(),
                ByVal ReportErrors As Boolean) As Object
 
            Return InternalLateInvokeDefault(Instance, Arguments, ArgumentNames, ReportErrors, IDOBinder.GetCopyBack())
        End Function
 
        ' LateGetInvokeDefault is used to optionally invoke the default action.
        ' If the arguments are non-empty, then it isn't optional, and is treated
        ' as an error if there is no default action.
        ' Currently we can get here only in the process of execution of NewLateBinding.LateGet.
        <System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)>
        <DebuggerHiddenAttribute()> <DebuggerStepThroughAttribute()>
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Public Shared Function LateGetInvokeDefault(
                ByVal Instance As Object,
                ByVal Arguments As Object(),
                ByVal ArgumentNames As String(),
                ByVal ReportErrors As Boolean) As Object
 
            ' According to a comment in VBGetBinder.FallbackInvoke, this function is called when
            ' "The DLR was able to resolve o.member, but not o.member(args)"
            ' When NewLateBinding.LateGet is evaluating similar expression itself, it never tries to invoke default action
            ' if arguments are not empty. It simply returns result of evaluating o.member. I believe, it makes sense
            ' to follow the same logic here. I.e., if there are no arguments, simply return the instance unless it is an IDO.
 
            If IDOUtils.TryCastToIDMOP(Instance) IsNot Nothing OrElse
                (Arguments IsNot Nothing AndAlso Arguments.Length > 0) _
            Then
                Return InternalLateInvokeDefault(Instance, Arguments, ArgumentNames, ReportErrors, IDOBinder.GetCopyBack())
            Else
                Return Instance
            End If
        End Function
 
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Private Shared Function InternalLateInvokeDefault(
                ByVal instance As Object,
                ByVal arguments As Object(),
                ByVal argumentNames As String(),
                ByVal reportErrors As Boolean,
                ByVal copyBack As Boolean()) As Object
 
            Dim idmop As IDynamicMetaObjectProvider = IDOUtils.TryCastToIDMOP(instance)
            If idmop IsNot Nothing Then
                Return IDOBinder.IDOInvokeDefault(idmop, arguments, argumentNames, reportErrors, copyBack)
            Else
                Return ObjectLateInvokeDefault(instance, arguments, argumentNames, reportErrors, copyBack)
            End If
        End Function
 
        'This method is only called from DynamicMethods generated at runtime
        <Obsolete("FallbackInvokeDefault1 has been deprecated and is not supported.", True)>
        <System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)>
        <DebuggerHiddenAttribute()> <DebuggerStepThroughAttribute()>
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Public Shared Function FallbackInvokeDefault1(
                ByVal Instance As Object,
                ByVal Arguments As Object(),
                ByVal ArgumentNames As String(),
                ByVal ReportErrors As Boolean) As Object
 
            ' Try using the IDO index operation (in case it's an IDO array)
            Return IDOBinder.IDOFallbackInvokeDefault(DirectCast(Instance, IDynamicMetaObjectProvider), Arguments, ArgumentNames, ReportErrors, IDOBinder.GetCopyBack())
        End Function
 
        'This method is only called from DynamicMethods generated at runtime
        <Obsolete("FallbackInvokeDefault2 has been deprecated and is not supported.", True)>
        <System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)>
        <DebuggerHiddenAttribute()> <DebuggerStepThroughAttribute()>
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Public Shared Function FallbackInvokeDefault2(
                ByVal Instance As Object,
                ByVal Arguments As Object(),
                ByVal ArgumentNames As String(),
                ByVal ReportErrors As Boolean) As Object
 
            Return ObjectLateInvokeDefault(Instance, Arguments, ArgumentNames, ReportErrors, IDOBinder.GetCopyBack())
        End Function
 
        <DebuggerHiddenAttribute()> <DebuggerStepThroughAttribute()>
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Private Shared Function ObjectLateInvokeDefault(
                ByVal instance As Object,
                ByVal arguments As Object(),
                ByVal argumentNames As String(),
                ByVal reportErrors As Boolean,
                ByVal copyBack As Boolean()) As Object
 
            Dim baseReference As Container = New Container(instance)
            Dim failure As ResolutionFailure
            Dim result As Object = InternalLateIndexGet(
                instance, arguments, argumentNames,
                reportErrors OrElse arguments.Length <> 0 OrElse baseReference.IsArray,
                failure, copyBack)
            Return If(failure = ResolutionFailure.None, result, instance)
        End Function
 
        <DebuggerHiddenAttribute(), DebuggerStepThroughAttribute()>
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Public Shared Function LateIndexGet(
                ByVal Instance As Object,
                ByVal Arguments() As Object,
                ByVal ArgumentNames() As String) As Object
 
            Return InternalLateInvokeDefault(Instance, Arguments, ArgumentNames, True, Nothing)
        End Function
 
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Private Shared Function LateIndexGet(
                ByVal instance As Object,
                ByVal arguments() As Object,
                ByVal argumentNames() As String,
                ByVal copyBack As Boolean()) As Object
 
            Return InternalLateInvokeDefault(instance, arguments, argumentNames, True, copyBack)
        End Function
 
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Private Shared Function InternalLateIndexGet(
                ByVal instance As Object,
                ByVal arguments() As Object,
                ByVal argumentNames() As String,
                ByVal reportErrors As Boolean,
                ByRef failure As ResolutionFailure,
                ByVal copyBack As Boolean()) As Object
 
            failure = ResolutionFailure.None
 
            If arguments Is Nothing Then arguments = NoArguments
            If argumentNames Is Nothing Then argumentNames = NoArgumentNames
 
            Dim baseReference As Container = New Container(instance)
            If baseReference.IsCOMObject AndAlso Not baseReference.IsWindowsRuntimeObject Then
                Return LateBinding.LateIndexGet(instance, arguments, argumentNames)
            End If
 
            'An r-value expression o(a) has two possible forms:
            '    1: o(a)    array lookup--where o is an array object and a is a set of indices
            '    2: o.d(a)  default member access--where o has default method/property d
 
            If baseReference.IsArray Then
                'This is an array lookup o(a).
 
                If argumentNames.Length > 0 Then
                    failure = ResolutionFailure.InvalidArgument
 
                    If reportErrors Then
                        Throw New ArgumentException(SR.Argument_InvalidNamedArgs)
                    End If
 
                    Return Nothing
                End If
 
                ' Initialize the copy back array to all ByVal
                ResetCopyback(copyBack)
                Return baseReference.GetArrayValue(arguments)
            End If
 
            'This is a default member access o.d(a), which is a call to method "".
            Return CallMethod(
                       baseReference,
                       "",
                       arguments,
                       argumentNames,
                       NoTypeArguments,
                       copyBack,
                       BindingFlagsInvokeMethod Or BindingFlagsGetProperty,
                       reportErrors,
                       failure)
        End Function
 
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Friend Shared Function CanBindInvokeDefault(
                ByVal instance As Object,
                ByVal arguments As Object(),
                ByVal argumentNames As String(),
                ByVal reportErrors As Boolean) As Boolean
 
            Dim baseReference As Container = New Container(instance)
            reportErrors = reportErrors OrElse arguments.Length <> 0 OrElse baseReference.IsArray
 
            If Not reportErrors Then
                Return True
            End If
 
            'An r-value expression o(a) has two possible forms:
            '    1: o(a)    array lookup--where o is an array object and a is a set of indices
            '    2: o.d(a)  default member access--where o has default method/property d
 
            If baseReference.IsArray Then
                'This is an array lookup o(a).
                Return argumentNames.Length = 0
            End If
 
            'This is a default member access o.d(a), which is a call to method "".
            Return CanBindCall(instance, "", arguments, argumentNames, False)
        End Function
 
        Friend Shared Sub ResetCopyback(ByVal copyBack As Boolean())
            If copyBack IsNot Nothing Then
                ' Initialize the copy back array to all ByVal.
                For index As Integer = 0 To copyBack.Length - 1
                    copyBack(index) = False
                Next
            End If
        End Sub
 
        <DebuggerHiddenAttribute(), DebuggerStepThroughAttribute()>
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Public Shared Function LateGet(
                ByVal Instance As Object,
                ByVal Type As System.Type,
                ByVal MemberName As String,
                ByVal Arguments As Object(),
                ByVal ArgumentNames As String(),
                ByVal TypeArguments As Type(),
                ByVal CopyBack As Boolean()) As Object
 
            If Arguments Is Nothing Then Arguments = NoArguments
            If ArgumentNames Is Nothing Then ArgumentNames = NoArgumentNames
            If TypeArguments Is Nothing Then TypeArguments = NoTypeArguments
 
            Dim baseReference As Container
            If Type IsNot Nothing Then
                baseReference = New Container(Type)
            Else
                baseReference = New Container(Instance)
            End If
 
            If baseReference.IsCOMObject AndAlso Not baseReference.IsWindowsRuntimeObject Then
                Return LateBinding.LateGet(Instance, Type, MemberName, Arguments, ArgumentNames, CopyBack)
            End If
 
            Dim invocationFlags As BindingFlags = BindingFlagsInvokeMethod Or BindingFlagsGetProperty
 
            Dim idmop As IDynamicMetaObjectProvider = IDOUtils.TryCastToIDMOP(Instance)
            If idmop IsNot Nothing AndAlso TypeArguments Is NoTypeArguments Then
                Return IDOBinder.IDOGet(idmop, MemberName, Arguments, ArgumentNames, CopyBack)
            Else
                Return ObjectLateGet(Instance, Type, MemberName, Arguments, ArgumentNames, TypeArguments, CopyBack)
            End If
        End Function 'LateGet
 
        'This method is only called from DynamicMethods generated at runtime
        <Obsolete("FallbackGet has been deprecated and is not supported.", True)>
        <System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)>
        <DebuggerHiddenAttribute()> <DebuggerStepThroughAttribute()>
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Public Shared Function FallbackGet(
                ByVal Instance As Object,
                ByVal MemberName As String,
                ByVal Arguments As Object(),
                ByVal ArgumentNames As String()) As Object
 
            Return ObjectLateGet(Instance, Nothing, MemberName, Arguments, ArgumentNames, NoTypeArguments, IDOBinder.GetCopyBack())
        End Function 'FallbackGet
 
        <DebuggerHiddenAttribute(), DebuggerStepThroughAttribute()>
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Private Shared Function ObjectLateGet(
                ByVal instance As Object,
                ByVal type As System.Type,
                ByVal memberName As String,
                ByVal arguments As Object(),
                ByVal argumentNames As String(),
                ByVal typeArguments As Type(),
                ByVal copyBack As Boolean()) As Object
 
            Dim baseReference As Container
            If type IsNot Nothing Then
                baseReference = New Container(type)
            Else
                baseReference = New Container(instance)
            End If
 
            Dim invocationFlags As BindingFlags = BindingFlagsInvokeMethod Or BindingFlagsGetProperty
 
            Dim members As MemberInfo() = baseReference.GetMembers(memberName, True)
 
            If members(0).MemberType = MemberTypes.Field Then
                If typeArguments.Length > 0 Then
                    Throw New ArgumentException(SR.Argument_InvalidValue)
                End If
 
                Dim fieldValue As Object = baseReference.GetFieldValue(DirectCast(members(0), FieldInfo))
                If arguments.Length = 0 Then
                    'This is a simple field access.
                    Return fieldValue
                Else
                    'This is an indexed field access.
                    Return LateIndexGet(fieldValue, arguments, argumentNames, copyBack)
                End If
            End If
 
            If argumentNames.Length > arguments.Length OrElse
               (copyBack IsNot Nothing AndAlso copyBack.Length <> arguments.Length) Then
                Throw New ArgumentException(SR.Argument_InvalidValue)
            End If
 
            Dim failure As OverloadResolution.ResolutionFailure
            Dim targetProcedure As Method =
                ResolveCall(
                    baseReference,
                    memberName,
                    members,
                    arguments,
                    argumentNames,
                    typeArguments,
                    invocationFlags,
                    False,
                    failure)
 
            If failure = OverloadResolution.ResolutionFailure.None Then
                Return baseReference.InvokeMethod(targetProcedure, arguments, copyBack, invocationFlags)
 
            ElseIf arguments.Length > 0 AndAlso members.Length = 1 AndAlso IsZeroArgumentCall(members(0)) Then
                ' Dev10 #579405: For default property transformation the group should contain just 1 item
                '                and that item should take no arguments.
 
                targetProcedure =
                    ResolveCall(
                        baseReference,
                        memberName,
                        members,
                        NoArguments,
                        NoArgumentNames,
                        typeArguments,
                        invocationFlags,
                        False,
                        failure)
 
                If failure = OverloadResolution.ResolutionFailure.None Then
                    Dim result As Object = baseReference.InvokeMethod(targetProcedure, NoArguments, Nothing, invocationFlags)
 
                    'For backwards compatibility, throw a missing member exception if the intermediate result is Nothing.
                    If result Is Nothing Then
                        Throw New MissingMemberException(
                                SR.Format(
                                    SR.IntermediateLateBoundNothingResult1,
                                    targetProcedure.ToString,
                                    baseReference.VBFriendlyName))
                    End If
 
                    result = InternalLateIndexGet(
                                result,
                                arguments,
                                argumentNames,
                                False,
                                failure,
                                copyBack)
 
                    If failure = ResolutionFailure.None Then
                        Return result
                    End If
                End If
 
            End If
 
            'Every attempt to make this work failed.  Redo the original call resolution to generate errors.
            ResolveCall(
                baseReference,
                memberName,
                members,
                arguments,
                argumentNames,
                typeArguments,
                invocationFlags,
                True,
                failure)
            Debug.Assert(False, "the resolution should have thrown an exception")
            Throw New InternalErrorException()
        End Function 'ObjectLateGet
 
        'Quick check to determine if FallbackGet will succeed
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Friend Shared Function CanBindGet(ByVal instance As Object, ByVal memberName As String, ByVal arguments As Object(), ByVal argumentNames As String()) As Boolean
            Dim baseReference As New Container(instance)
            Dim invocationFlags As BindingFlags = BindingFlagsInvokeMethod Or BindingFlagsGetProperty
 
            Dim failure As ResolutionFailure
            Dim members As MemberInfo() = baseReference.GetMembers(memberName, False)
            If members Is Nothing OrElse members.Length = 0 Then
                Return False
            End If
 
            If members(0).MemberType = MemberTypes.Field Then
                'There may be additional work after the field get, but as far
                'as we're concerned the binding succeeded
                Return True
            End If
 
            Dim targetProcedure As Method =
                ResolveCall(
                    baseReference,
                    memberName,
                    members,
                    arguments,
                    argumentNames,
                    NoTypeArguments,
                    invocationFlags,
                    False,
                    failure)
 
            If failure = OverloadResolution.ResolutionFailure.None Then
                Return True
            End If
 
            If arguments.Length > 0 AndAlso members.Length = 1 AndAlso IsZeroArgumentCall(members(0)) Then
                ' Dev10 #579405: For default property transformation the group should contain just 1 item
                '                and that item should take no arguments.
 
                targetProcedure =
                    ResolveCall(
                        baseReference,
                        memberName,
                        members,
                        NoArguments,
                        NoArgumentNames,
                        NoTypeArguments,
                        invocationFlags,
                        False,
                        failure)
 
                If failure = OverloadResolution.ResolutionFailure.None Then
                    'There will be additional work after the first call, but as
                    'far as we're concerned the binding succeeded.
                    Return True
                End If
            End If
 
            'Every attempt at binding failed, return false so we use the IDO's error
            Return False
        End Function
 
        ' Determines if the member is a zero argument method or property
        Friend Shared Function IsZeroArgumentCall(ByVal member As MemberInfo) As Boolean
            Return ((member.MemberType = MemberTypes.Method AndAlso
                        DirectCast(member, MethodInfo).GetParameters().Length = 0) OrElse
                    (member.MemberType = MemberTypes.Property AndAlso
                        DirectCast(member, PropertyInfo).GetIndexParameters().Length = 0))
        End Function
 
        <DebuggerHiddenAttribute(), DebuggerStepThroughAttribute()>
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Public Shared Sub LateIndexSetComplex(
                ByVal Instance As Object,
                ByVal Arguments As Object(),
                ByVal ArgumentNames As String(),
                ByVal OptimisticSet As Boolean,
                ByVal RValueBase As Boolean)
 
            Dim idmop As IDynamicMetaObjectProvider = IDOUtils.TryCastToIDMOP(Instance)
            If idmop IsNot Nothing Then
                Call IDOBinder.IDOIndexSetComplex(idmop, Arguments, ArgumentNames, OptimisticSet, RValueBase)
            Else
                Call ObjectLateIndexSetComplex(Instance, Arguments, ArgumentNames, OptimisticSet, RValueBase)
                Return
            End If
        End Sub
 
        'This method is only called from DynamicMethods generated at runtime
        <Obsolete("FallbackIndexSetComplex has been deprecated and is not supported.", True)>
        <System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)>
        <DebuggerHiddenAttribute(), DebuggerStepThroughAttribute()>
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Public Shared Sub FallbackIndexSetComplex(
                ByVal Instance As Object,
                ByVal Arguments As Object(),
                ByVal ArgumentNames As String(),
                ByVal OptimisticSet As Boolean,
                ByVal RValueBase As Boolean)
 
            ObjectLateIndexSetComplex(Instance, Arguments, ArgumentNames, OptimisticSet, RValueBase)
        End Sub 'FallbackIndexSetComplex
 
        <DebuggerHiddenAttribute(), DebuggerStepThroughAttribute()>
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Friend Shared Sub ObjectLateIndexSetComplex(
                ByVal instance As Object,
                ByVal arguments As Object(),
                ByVal argumentNames As String(),
                ByVal optimisticSet As Boolean,
                ByVal rValueBase As Boolean)
 
            If arguments Is Nothing Then arguments = NoArguments
            If argumentNames Is Nothing Then argumentNames = NoArgumentNames
 
            Dim baseReference As Container = New Container(instance)
 
            'An l-value expression o(a) has two possible forms:
            '    1: o(a) = v    array lookup--where o is an array object and a is a set of indices
            '    2: o.d(a) = v  default member access--where o has default method/property d
 
            If baseReference.IsArray Then
                'This is an array lookup and assignment o(a) = v.
 
                If argumentNames.Length > 0 Then
                    Throw New ArgumentException(SR.Argument_InvalidNamedArgs)
                End If
 
                baseReference.SetArrayValue(arguments)
                Return
            End If
 
            If argumentNames.Length > arguments.Length Then
                Throw New ArgumentException(SR.Argument_InvalidValue)
            End If
 
            If arguments.Length < 1 Then
                'We're binding to a Set, we must have at least the Value argument.
                Throw New ArgumentException(SR.Argument_InvalidValue)
            End If
 
            Dim methodName As String = ""
            If baseReference.IsCOMObject AndAlso Not baseReference.IsWindowsRuntimeObject Then
                LateBinding.LateIndexSetComplex(instance, arguments, argumentNames, optimisticSet, rValueBase)
                Return
            End If
 
            Dim invocationFlags As BindingFlags = BindingFlagsSetProperty
 
            Dim members As MemberInfo() = baseReference.GetMembers(methodName, True) 'MethodName is set during this call.
 
            Dim failure As OverloadResolution.ResolutionFailure
            Dim targetProcedure As Method =
                ResolveCall(
                    baseReference,
                    methodName,
                    members,
                    arguments,
                    argumentNames,
                    NoTypeArguments,
                    invocationFlags,
                    False,
                    failure)
 
            If failure = OverloadResolution.ResolutionFailure.None Then
 
                If rValueBase AndAlso baseReference.IsValueType Then
                    Throw New Exception(
                            SR.Format(
                                SR.RValueBaseForValueType,
                                baseReference.VBFriendlyName,
                                baseReference.VBFriendlyName))
                End If
 
                baseReference.InvokeMethod(targetProcedure, arguments, Nothing, invocationFlags)
                Return
 
            ElseIf optimisticSet Then
                Return
 
            Else
                'Redo the resolution to generate errors.
                ResolveCall(
                    baseReference,
                    methodName,
                    members,
                    arguments,
                    argumentNames,
                    NoTypeArguments,
                    invocationFlags,
                    True,
                    failure)
            End If
 
 
            Debug.Assert(False, "the resolution should have thrown an exception - should never reach here")
            Throw New InternalErrorException()
 
        End Sub
 
        'Determines if ObjectLateIndexSetComplex can succeed
        'Used by IDOBinder
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Friend Shared Function CanIndexSetComplex(
                ByVal instance As Object,
                ByVal arguments As Object(),
                ByVal argumentNames As String(),
                ByVal optimisticSet As Boolean,
                ByVal rValueBase As Boolean) As Boolean
 
            Dim baseReference As Container = New Container(instance)
 
            'An l-value expression o(a) has two possible forms:
            '    1: o(a) = v    array lookup--where o is an array object and a is a set of indices
            '    2: o.d(a) = v  default member access--where o has default method/property d
 
            If baseReference.IsArray Then
                'This is an array lookup and assignment o(a) = v.
                Return argumentNames.Length = 0
            End If
 
            Dim methodName As String = ""
            Dim invocationFlags As BindingFlags = BindingFlagsSetProperty
 
            Dim members As MemberInfo() = baseReference.GetMembers(methodName, False) 'MethodName is set during this call.
            If members Is Nothing OrElse members.Length = 0 Then
                Return False
            End If
 
            Dim failure As OverloadResolution.ResolutionFailure
            Dim targetProcedure As Method =
                ResolveCall(
                    baseReference,
                    methodName,
                    members,
                    arguments,
                    argumentNames,
                    NoTypeArguments,
                    invocationFlags,
                    False,
                    failure)
 
            If failure = OverloadResolution.ResolutionFailure.None Then
                If rValueBase AndAlso baseReference.IsValueType Then
                    Return False
                End If
 
                Return True
            End If
 
            Return optimisticSet
        End Function
 
        <DebuggerHiddenAttribute(), DebuggerStepThroughAttribute()>
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Public Shared Sub LateIndexSet(
                ByVal Instance As Object,
                ByVal Arguments() As Object,
                ByVal ArgumentNames() As String)
 
            Dim idmop As IDynamicMetaObjectProvider = IDOUtils.TryCastToIDMOP(Instance)
            If idmop IsNot Nothing Then
                IDOBinder.IDOIndexSet(idmop, Arguments, ArgumentNames)
                Return
            Else
                ObjectLateIndexSet(Instance, Arguments, ArgumentNames)
                Return
            End If
        End Sub 'LateIndexSet
 
        'This method is only called from DynamicMethods generated at runtime
        <Obsolete("FallbackIndexSet has been deprecated and is not supported.", True)>
        <System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)>
        <DebuggerHiddenAttribute()> <DebuggerStepThroughAttribute()>
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Public Shared Sub FallbackIndexSet(
                ByVal Instance As Object,
                ByVal Arguments() As Object,
                ByVal ArgumentNames() As String)
 
            ObjectLateIndexSet(Instance, Arguments, ArgumentNames)
        End Sub 'FallbackIndexSet
 
        <DebuggerHiddenAttribute(), DebuggerStepThroughAttribute()>
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Private Shared Sub ObjectLateIndexSet(
                ByVal Instance As Object,
                ByVal Arguments() As Object,
                ByVal ArgumentNames() As String)
 
            ObjectLateIndexSetComplex(Instance, Arguments, ArgumentNames, False, False)
            Return
        End Sub 'ObjectLateIndexSet
 
        <DebuggerHiddenAttribute(), DebuggerStepThroughAttribute()>
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Public Shared Sub LateSetComplex(
                ByVal Instance As Object,
                ByVal Type As Type,
                ByVal MemberName As String,
                ByVal Arguments() As Object,
                ByVal ArgumentNames() As String,
                ByVal TypeArguments() As Type,
                ByVal OptimisticSet As Boolean,
                ByVal RValueBase As Boolean)
 
            Dim idmop As IDynamicMetaObjectProvider = IDOUtils.TryCastToIDMOP(Instance)
            If idmop IsNot Nothing AndAlso TypeArguments Is Nothing Then
                IDOBinder.IDOSetComplex(idmop, MemberName, Arguments, ArgumentNames, OptimisticSet, RValueBase)
            Else
                ObjectLateSetComplex(Instance, Type,
                    MemberName, Arguments, ArgumentNames, TypeArguments, OptimisticSet, RValueBase)
                Return
            End If
        End Sub
 
        'This method is only called from DynamicMethods generated at runtime
        <Obsolete("FallbackSetComplex has been deprecated and is not supported.", True)>
        <System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)>
        <DebuggerHiddenAttribute(), DebuggerStepThroughAttribute()>
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Public Shared Sub FallbackSetComplex(
                ByVal Instance As Object,
                ByVal MemberName As String,
                ByVal Arguments() As Object,
                ByVal OptimisticSet As Boolean,
                ByVal RValueBase As Boolean)
 
            ObjectLateSetComplex(
                Instance, Nothing, MemberName, Arguments, Array.Empty(Of String)(),
                NoTypeArguments, OptimisticSet, RValueBase)
        End Sub 'FallbackSetComplex
 
        <DebuggerHiddenAttribute(), DebuggerStepThroughAttribute()>
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Friend Shared Sub ObjectLateSetComplex(
                ByVal instance As Object,
                ByVal type As Type,
                ByVal memberName As String,
                ByVal arguments() As Object,
                ByVal argumentNames() As String,
                ByVal typeArguments() As Type,
                ByVal optimisticSet As Boolean,
                ByVal rValueBase As Boolean)
 
            Const defaultCallType As CallType = CType(0, CallType)
            LateSet(instance, type, memberName, arguments, argumentNames, typeArguments, optimisticSet, rValueBase, defaultCallType)
        End Sub
 
        <DebuggerHiddenAttribute(), DebuggerStepThroughAttribute()>
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Public Shared Sub LateSet(
                ByVal Instance As Object,
                ByVal Type As Type,
                ByVal MemberName As String,
                ByVal Arguments() As Object,
                ByVal ArgumentNames() As String,
                ByVal TypeArguments As Type())
 
            Dim idmop As IDynamicMetaObjectProvider = IDOUtils.TryCastToIDMOP(Instance)
            If idmop IsNot Nothing AndAlso TypeArguments Is Nothing Then
                IDOBinder.IDOSet(idmop, MemberName, ArgumentNames, Arguments)
            Else
                ObjectLateSet(Instance, Type, MemberName, Arguments, ArgumentNames, TypeArguments)
                Return
            End If
        End Sub
 
        'This method is only called from DynamicMethods generated at runtime
        <Obsolete("FallbackSet has been deprecated and is not supported.", True)>
        <System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)>
        <DebuggerHiddenAttribute(), DebuggerStepThroughAttribute()>
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Public Shared Sub FallbackSet(
                ByVal Instance As Object,
                ByVal MemberName As String,
                ByVal Arguments() As Object)
 
            ObjectLateSet(Instance, Nothing, MemberName, Arguments, NoArgumentNames, NoTypeArguments)
        End Sub
 
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Friend Shared Sub ObjectLateSet(
                ByVal instance As Object,
                ByVal type As Type,
                ByVal memberName As String,
                ByVal arguments() As Object,
                ByVal argumentNames() As String,
                ByVal typeArguments As Type())
 
            Const defaultCallType As CallType = CType(0, CallType)
            LateSet(instance, type, memberName, arguments, argumentNames,
                typeArguments, False, False, defaultCallType)
            Return
        End Sub
 
        <DebuggerHiddenAttribute(), DebuggerStepThroughAttribute()>
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Public Shared Sub LateSet(
                ByVal Instance As Object,
                ByVal Type As Type,
                ByVal MemberName As String,
                ByVal Arguments As Object(),
                ByVal ArgumentNames As String(),
                ByVal TypeArguments As Type(),
                ByVal OptimisticSet As Boolean,
                ByVal RValueBase As Boolean,
                ByVal CallType As CallType)
 
            If Arguments Is Nothing Then Arguments = NoArguments
            If ArgumentNames Is Nothing Then ArgumentNames = NoArgumentNames
            If TypeArguments Is Nothing Then TypeArguments = NoTypeArguments
 
            Dim baseReference As Container
            If Type IsNot Nothing Then
                baseReference = New Container(Type)
            Else
                baseReference = New Container(Instance)
            End If
 
            If baseReference.IsCOMObject AndAlso Not baseReference.IsWindowsRuntimeObject Then
                Try
                    LateBinding.InternalLateSet(Instance, Type, MemberName, Arguments, ArgumentNames, OptimisticSet, CallType)
                    If RValueBase And Type.IsValueType Then
                        Throw New Exception(Utils.GetResourceString(SR.RValueBaseForValueType, baseReference.VBFriendlyName, baseReference.VBFriendlyName))
                    End If
                    Return
                Catch ex As MissingMemberException When OptimisticSet
                    Return
                End Try
            End If
 
            Dim invocationFlags As BindingFlags
 
            ' If we have a IDO that implements TryGetMember for a property but not TrySetMember then we could land up
            ' here and with an optimistic set but we don't want to throw an exception if the property is not found.
            ' Swallow the exception and return quietly if this is a readonly IDO property doing an optimistic set.
            Dim members As MemberInfo() = baseReference.GetMembers(MemberName, Not OptimisticSet)
 
            If members.Length = 0 And OptimisticSet Then
                Return
            End If
 
            If members(0).MemberType = MemberTypes.Field Then
 
                If TypeArguments.Length > 0 Then
                    Throw New ArgumentException(SR.Argument_InvalidValue)
                End If
 
                If Arguments.Length = 1 Then
                    If RValueBase AndAlso baseReference.IsValueType Then
                        Throw New Exception(
                                SR.Format(
                                    SR.RValueBaseForValueType,
                                    baseReference.VBFriendlyName,
                                    baseReference.VBFriendlyName))
                    End If
                    'This is a simple field set.
                    baseReference.SetFieldValue(DirectCast(members(0), FieldInfo), Arguments(0))
                    Return
                Else
                    'This is an indexed field set.
                    Dim fieldValue As Object = baseReference.GetFieldValue(DirectCast(members(0), FieldInfo))
                    LateIndexSetComplex(fieldValue, Arguments, ArgumentNames, OptimisticSet, True)
                    Return
                End If
            End If
 
            invocationFlags = BindingFlagsSetProperty
 
            If ArgumentNames.Length > Arguments.Length Then
                Throw New ArgumentException(SR.Argument_InvalidValue)
            End If
 
            Dim failure As OverloadResolution.ResolutionFailure
            Dim targetProcedure As Method
 
            If TypeArguments.Length = 0 Then
 
                targetProcedure =
                    ResolveCall(
                        baseReference,
                        MemberName,
                        members,
                        Arguments,
                        ArgumentNames,
                        NoTypeArguments,
                        invocationFlags,
                        False,
                        failure)
 
                If failure = OverloadResolution.ResolutionFailure.None Then
                    If RValueBase AndAlso baseReference.IsValueType Then
                        Throw New Exception(
                                SR.Format(
                                    SR.RValueBaseForValueType,
                                    baseReference.VBFriendlyName,
                                    baseReference.VBFriendlyName))
                    End If
 
                    baseReference.InvokeMethod(targetProcedure, Arguments, Nothing, invocationFlags)
                    Return
                End If
 
            End If
 
            Dim secondaryInvocationFlags As BindingFlags =
                    BindingFlagsInvokeMethod Or BindingFlagsGetProperty
 
            If failure = OverloadResolution.ResolutionFailure.None OrElse failure = OverloadResolution.ResolutionFailure.MissingMember Then
 
                targetProcedure =
                    ResolveCall(
                        baseReference,
                        MemberName,
                        members,
                        NoArguments,
                        NoArgumentNames,
                        TypeArguments,
                        secondaryInvocationFlags,
                        False,
                        failure)
 
                If failure = OverloadResolution.ResolutionFailure.None Then
                    Dim result As Object =
                        baseReference.InvokeMethod(targetProcedure, NoArguments, Nothing, secondaryInvocationFlags)
 
                    'For backwards compatibility, throw a missing member exception if the intermediate result is Nothing.
                    If result Is Nothing Then
                        Throw New MissingMemberException(
                                SR.Format(
                                    SR.IntermediateLateBoundNothingResult1,
                                    targetProcedure.ToString,
                                    baseReference.VBFriendlyName))
                    End If
 
                    LateIndexSetComplex(result, Arguments, ArgumentNames, OptimisticSet, True)
                    Return
                End If
            End If
 
            If OptimisticSet Then
                Return
            End If
 
            'Everything failed, so give errors. Redo the first attempt to generate the errors.
            If TypeArguments.Length = 0 Then
                ResolveCall(
                    baseReference,
                    MemberName,
                    members,
                    Arguments,
                    ArgumentNames,
                    TypeArguments,
                    invocationFlags,
                    True,
                    failure)
 
            Else
                ResolveCall(
                    baseReference,
                    MemberName,
                    members,
                    NoArguments,
                    NoArgumentNames,
                    TypeArguments,
                    secondaryInvocationFlags,
                    True,
                    failure)
            End If
 
            Debug.Assert(False, "the resolution should have thrown an exception")
            Throw New InternalErrorException()
            Return
        End Sub
 
        'Determines if LateSet will succeed. Used by IDOBinder.
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Friend Shared Function CanBindSet(ByVal instance As Object, ByVal memberName As String, ByVal value As Object, ByVal optimisticSet As Boolean, ByVal rValueBase As Boolean) As Boolean
            Dim baseReference As New Container(instance)
            Dim arguments As Object() = {value}
 
            Dim members As MemberInfo() = baseReference.GetMembers(memberName, False)
            If members Is Nothing OrElse members.Length = 0 Then
                Return False
            End If
 
            If members(0).MemberType = MemberTypes.Field Then
                If arguments.Length = 1 AndAlso rValueBase AndAlso baseReference.IsValueType Then
                    Return False
                End If
 
                'There may be more work (for indexed fields), but if we got
                'this far we consider it success.
                Return True
            End If
 
            Dim failure As OverloadResolution.ResolutionFailure
            Dim targetProcedure As Method =
                ResolveCall(
                    baseReference,
                    memberName,
                    members,
                    arguments,
                    NoArgumentNames,
                    NoTypeArguments,
                    BindingFlagsSetProperty,
                    False,
                    failure)
 
            If failure = OverloadResolution.ResolutionFailure.None Then
                If rValueBase AndAlso baseReference.IsValueType Then
                    Return False
                End If
 
                Return True
            End If
 
            Dim secondaryInvocationFlags As BindingFlags = BindingFlagsInvokeMethod Or BindingFlagsGetProperty
 
            If failure = OverloadResolution.ResolutionFailure.MissingMember Then
                targetProcedure =
                    ResolveCall(
                        baseReference,
                        memberName,
                        members,
                        NoArguments,
                        NoArgumentNames,
                        NoTypeArguments,
                        secondaryInvocationFlags,
                        False,
                        failure)
 
                If failure = OverloadResolution.ResolutionFailure.None Then
                    'There is work (to call the method/prop), but if we got
                    'this far we consider it success.
                    Return True
                End If
            End If
 
            'Everything failed, so use the IDO's error if any
            'Unless we're doing an optimistic set, in which case this is considered success.
            Return optimisticSet
        End Function
 
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Private Shared Function CallMethod(
                ByVal baseReference As Container,
                ByVal methodName As String,
                ByVal arguments As Object(),
                ByVal argumentNames As String(),
                ByVal typeArguments As System.Type(),
                ByVal copyBack As Boolean(),
                ByVal invocationFlags As BindingFlags,
                ByVal reportErrors As Boolean,
                ByRef failure As ResolutionFailure) As Object
 
            Debug.Assert(baseReference IsNot Nothing, "Nothing unexpected")
            Debug.Assert(arguments IsNot Nothing, "Nothing unexpected")
            Debug.Assert(argumentNames IsNot Nothing, "Nothing unexpected")
            Debug.Assert(typeArguments IsNot Nothing, "Nothing unexpected")
 
            failure = ResolutionFailure.None
 
            If argumentNames.Length > arguments.Length OrElse
               (copyBack IsNot Nothing AndAlso copyBack.Length <> arguments.Length) Then
                failure = ResolutionFailure.InvalidArgument
 
                If reportErrors Then
                    Throw New ArgumentException(SR.Argument_InvalidValue)
                End If
 
                Return Nothing
            End If
 
            If HasFlag(invocationFlags, BindingFlagsSetProperty) AndAlso arguments.Length < 1 Then
                failure = ResolutionFailure.InvalidArgument
 
                If reportErrors Then
                    'If we're binding to a Set, we must have at least the Value argument.
                    Throw New ArgumentException(SR.Argument_InvalidValue)
                End If
 
                Return Nothing
            End If
 
            Dim members As MemberInfo() = baseReference.GetMembers(methodName, reportErrors)
 
            If members Is Nothing OrElse members.Length = 0 Then
                failure = ResolutionFailure.MissingMember
 
                If reportErrors Then
                    Debug.Assert(False, "If ReportErrors is True, GetMembers should have thrown above")
                    members = baseReference.GetMembers(methodName, True)
                End If
 
                Return Nothing
            End If
 
            Dim targetProcedure As Method =
                ResolveCall(
                    baseReference,
                    methodName,
                    members,
                    arguments,
                    argumentNames,
                    typeArguments,
                    invocationFlags,
                    reportErrors,
                    failure)
 
            If failure = ResolutionFailure.None Then
                Return baseReference.InvokeMethod(targetProcedure, arguments, copyBack, invocationFlags)
            End If
 
            Return Nothing
        End Function
 
        Friend Shared Function MatchesPropertyRequirements(ByVal targetProcedure As Method, ByVal flags As BindingFlags) As MethodInfo
            Debug.Assert(targetProcedure.IsProperty, "advertised property method isn't.")
 
            Dim propInfo As PropertyInfo = targetProcedure.AsProperty()
            If HasFlag(flags, BindingFlagsSetProperty) Then
                Return If(HasIsExternalInitModifier(propInfo.GetSetMethod), Nothing, propInfo.GetSetMethod)
            Else
                Return propInfo.GetGetMethod
            End If
        End Function
 
        Friend Shared Function ReportPropertyMismatch(ByVal targetProcedure As Method, ByVal flags As BindingFlags) As Exception
            Debug.Assert(targetProcedure.IsProperty, "advertised property method isn't.")
 
            Dim propInfo As PropertyInfo = targetProcedure.AsProperty()
            If HasFlag(flags, BindingFlagsSetProperty) Then
                Debug.Assert(propInfo.GetSetMethod Is Nothing OrElse HasIsExternalInitModifier(propInfo.GetSetMethod), "expected error condition")
                Return New MissingMemberException(
                    SR.Format(SR.NoSetProperty1, propInfo.Name))
            Else
                Debug.Assert(propInfo.GetGetMethod Is Nothing, "expected error condition")
                Return New MissingMemberException(
                    SR.Format(SR.NoGetProperty1, propInfo.Name))
            End If
        End Function
 
        Private Shared Function HasIsExternalInitModifier(method As MethodInfo) As Boolean
            Dim customModifierTypes As Type() = method?.ReturnParameter.GetRequiredCustomModifiers()
            If customModifierTypes IsNot Nothing Then
                For Each customModifierType As Type In customModifierTypes
                    If customModifierType.Name = "IsExternalInit" AndAlso Not customModifierType.IsNested AndAlso customModifierType.Namespace = "System.Runtime.CompilerServices" Then
                        Return True
                    End If
                Next
            End If
            Return False
        End Function
 
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Friend Shared Function ResolveCall(
                ByVal baseReference As Container,
                ByVal methodName As String,
                ByVal members As MemberInfo(),
                ByVal arguments As Object(),
                ByVal argumentNames As String(),
                ByVal typeArguments As Type(),
                ByVal lookupFlags As BindingFlags,
                ByVal reportErrors As Boolean,
                ByRef failure As OverloadResolution.ResolutionFailure) As Method
 
            Debug.Assert(baseReference IsNot Nothing, "expected a base reference")
            Debug.Assert(methodName IsNot Nothing, "expected method name")
            Debug.Assert(members IsNot Nothing AndAlso members.Length > 0, "expected members")
            Debug.Assert(arguments IsNot Nothing AndAlso
                         argumentNames IsNot Nothing AndAlso
                         typeArguments IsNot Nothing AndAlso
                         argumentNames.Length <= arguments.Length,
                         "expected valid argument arrays")
 
            failure = OverloadResolution.ResolutionFailure.None
 
            If members(0).MemberType <> MemberTypes.Method AndAlso
               members(0).MemberType <> MemberTypes.Property Then
 
                failure = OverloadResolution.ResolutionFailure.InvalidTarget
                If reportErrors Then
                    'This expression is not a procedure, but occurs as the target of a procedure call.
                    Throw New ArgumentException(
                        SR.Format(SR.ExpressionNotProcedure, methodName, baseReference.VBFriendlyName))
                End If
                Return Nothing
            End If
 
            'When binding to Property Set accessors, strip off the last Value argument
            'because it does not participate in overload resolution.
 
            Dim savedArguments As Object()
            Dim argumentCount As Integer = arguments.Length
            Dim lastArgument As Object = Nothing
 
            If HasFlag(lookupFlags, BindingFlagsSetProperty) Then
                If arguments.Length = 0 Then
                    failure = OverloadResolution.ResolutionFailure.InvalidArgument
 
                    If reportErrors Then
                        Throw New InvalidCastException(
                            SR.Format(SR.PropertySetMissingArgument1, methodName))
                    End If
 
                    Return Nothing
                End If
 
                savedArguments = arguments
                arguments = New Object(argumentCount - 2) {}
                System.Array.Copy(savedArguments, arguments, arguments.Length)
                lastArgument = savedArguments(argumentCount - 1)
            End If
 
            Dim resolutionResult As Method =
                ResolveOverloadedCall(
                    methodName,
                    members,
                    arguments,
                    argumentNames,
                    typeArguments,
                    lookupFlags,
                    reportErrors,
                    failure,
                    baseReference)
 
            Debug.Assert(failure = OverloadResolution.ResolutionFailure.None OrElse Not reportErrors,
                         "if resolution failed, an exception should have been thrown")
 
            If failure <> OverloadResolution.ResolutionFailure.None Then
                Debug.Assert(resolutionResult Is Nothing, "resolution failed so should have no result")
                Return Nothing
            End If
 
            Debug.Assert(resolutionResult IsNot Nothing, "resolution didn't fail, so should have result")
 
#If BINDING_LOG Then
            Console.WriteLine("== RESULT ==")
            Console.WriteLine(ResolutionResult.DeclaringType.Name & "::" & ResolutionResult.ToString)
            Console.WriteLine()
#End If
 
            'Overload resolution will potentially select one method before validating arguments.
            'Validate those arguments now.
            If Not resolutionResult.ArgumentsValidated Then
 
                If Not CanMatchArguments(resolutionResult, arguments, argumentNames, typeArguments, False, Nothing) Then
 
                    failure = OverloadResolution.ResolutionFailure.InvalidArgument
 
                    If reportErrors Then
                        Dim errorMessage As String = ""
                        Dim errors As New List(Of String)
 
                        Dim result As Boolean =
                            CanMatchArguments(resolutionResult, arguments, argumentNames, typeArguments, False, errors)
 
                        Debug.Assert(result = False AndAlso errors.Count > 0, "expected this candidate to fail")
 
                        For Each errorString As String In errors
                            errorMessage &= vbCrLf & "    " & errorString
                        Next
 
                        errorMessage = SR.Format(SR.MatchArgumentFailure2, resolutionResult.ToString, errorMessage)
                        'We are missing a member which can match the arguments, so throw a missing member exception.
                        'The InvalidCastException is thrown only for back compat.  It would
                        'be nice if the latebinder had its own set of exceptions to throw.
                        Throw New InvalidCastException(errorMessage)
                    End If
 
                    Return Nothing
                End If
 
            End If
 
            'Once we've gotten this far, we've selected a member. From this point on, we determine
            'if the member can be called given the context.
 
            'Check that the resulting binding makes sense in the current context.
            If resolutionResult.IsProperty Then
                If MatchesPropertyRequirements(resolutionResult, lookupFlags) Is Nothing Then
                    failure = OverloadResolution.ResolutionFailure.InvalidTarget
                    If reportErrors Then
                        Throw ReportPropertyMismatch(resolutionResult, lookupFlags)
                    End If
                    Return Nothing
                End If
            Else
                Debug.Assert(resolutionResult.IsMethod, "must be a method")
                If HasFlag(lookupFlags, BindingFlagsSetProperty) Then
                    failure = OverloadResolution.ResolutionFailure.InvalidTarget
                    If reportErrors Then
                        'Methods can't be targets of assignments.
                        Throw New MissingMemberException(
                            SR.Format(SR.MethodAssignment1, resolutionResult.AsMethod.Name))
                    End If
                    Return Nothing
                End If
            End If
 
            If HasFlag(lookupFlags, BindingFlagsSetProperty) Then
                'Need to match the Value argument for the property set call.
                Debug.Assert(GetCallTarget(resolutionResult, lookupFlags).Name.StartsWith("set_"), "expected set accessor")
 
                Dim parameters As ParameterInfo() = GetCallTarget(resolutionResult, lookupFlags).GetParameters
                Dim lastParameter As ParameterInfo = parameters(parameters.Length - 1)
                If Not CanPassToParameter(
                            resolutionResult,
                            lastArgument,
                            lastParameter,
                            False,
                            False,
                            Nothing,
                            Nothing,
                            Nothing) Then
 
                    failure = OverloadResolution.ResolutionFailure.InvalidArgument
 
                    If reportErrors Then
                        Dim errorMessage As String = ""
                        Dim errors As New List(Of String)
 
                        Dim result As Boolean =
                            CanPassToParameter(
                                resolutionResult,
                                lastArgument,
                                lastParameter,
                                False,
                                False,
                                errors,
                                Nothing,
                                Nothing)
 
                        Debug.Assert(result = False AndAlso errors.Count > 0, "expected this candidate to fail")
 
                        For Each errorString As String In errors
                            errorMessage &= vbCrLf & "    " & errorString
                        Next
 
                        errorMessage = SR.Format(SR.MatchArgumentFailure2, resolutionResult.ToString, errorMessage)
                        'The selected member can't handle the type of the Value argument, so this is an argument exception.
                        'The InvalidCastException is thrown only for back compat.  It would
                        'be nice if the latebinder had its own set of exceptions to throw.
                        Throw New InvalidCastException(errorMessage)
                    End If
 
                    Return Nothing
                End If
            End If
 
            Return resolutionResult
        End Function
 
        Friend Shared Function GetCallTarget(ByVal targetProcedure As Method, ByVal flags As BindingFlags) As MethodBase
            If targetProcedure.IsMethod Then Return targetProcedure.AsMethod
            If targetProcedure.IsProperty Then Return MatchesPropertyRequirements(targetProcedure, flags)
            Debug.Assert(False, "not a method or property??")
            Return Nothing
        End Function
 
        <RequiresUnreferencedCode(LateBindingTrimMessage)>
        Friend Shared Function ConstructCallArguments(
            ByVal targetProcedure As Method,
            ByVal arguments As Object(),
            ByVal lookupFlags As BindingFlags) As Object()
 
            Debug.Assert(targetProcedure IsNot Nothing AndAlso arguments IsNot Nothing, "expected arguments")
 
 
            Dim parameters As ParameterInfo() = GetCallTarget(targetProcedure, lookupFlags).GetParameters
            Dim callArguments As Object() = New Object(parameters.Length - 1) {}
 
            Dim savedArguments As Object()
            Dim argumentCount As Integer = arguments.Length
            Dim lastArgument As Object = Nothing
 
            If HasFlag(lookupFlags, BindingFlagsSetProperty) Then
                Debug.Assert(arguments.Length > 0, "must have an argument for property set Value")
                savedArguments = arguments
                arguments = New Object(argumentCount - 2) {}
                System.Array.Copy(savedArguments, arguments, arguments.Length)
                lastArgument = savedArguments(argumentCount - 1)
            End If
 
            MatchArguments(targetProcedure, arguments, callArguments)
 
            If HasFlag(lookupFlags, BindingFlagsSetProperty) Then
                'Need to match the Value argument for the property set call.
                Debug.Assert(GetCallTarget(targetProcedure, lookupFlags).Name.StartsWith("set_"), "expected set accessor")
 
                Dim lastParameter As ParameterInfo = parameters(parameters.Length - 1)
                callArguments(parameters.Length - 1) =
                    PassToParameter(lastArgument, lastParameter, lastParameter.ParameterType)
            End If
 
            Return callArguments
        End Function
 
    End Class
End Namespace