Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En la práctica, las reglas para determinar la resolución de sobrecarga están pensadas para encontrar la sobrecarga "más cercana" a los argumentos reales proporcionados. Si hay un método cuyos tipos de parámetro coinciden con los tipos de argumento, ese método es obviamente el más cercano. Barring that, one method is closer than another if all of its parameter types are narrower than (or the same as) the parameter types of the other method. Si ninguno de los parámetros del método es más estrecho que el otro, no hay ninguna manera de determinar qué método está más cerca de los argumentos.
Nota. La resolución de sobrecarga no tiene en cuenta el tipo de valor devuelto esperado del método .
Tenga en cuenta también que, debido a la sintaxis de parámetros con nombre, es posible que la ordenación de los parámetros reales y formales no sea la misma.
Dado un grupo de métodos, el método más aplicable del grupo para una lista de argumentos se determina mediante los pasos siguientes. Si, después de aplicar un paso determinado, no se mantiene ningún miembro en el conjunto, se produce un error en tiempo de compilación. Si solo un miembro permanece en el conjunto, ese miembro es el miembro más aplicable. Los pasos son:
En primer lugar, si no se ha proporcionado ningún argumento de tipo, aplique la inferencia de tipos a cualquier método que tenga parámetros de tipo. Si la inferencia de tipos se realiza correctamente para un método, los argumentos de tipo inferido se usan para ese método determinado. Si se produce un error en la inferencia de tipos para un método, ese método se elimina del conjunto.
A continuación, elimine todos los miembros del conjunto que no son accesibles o no aplicables ( Aplicabilidad de sección a lista de argumentos) a la lista de argumentos.
A continuación, si uno o varios argumentos son
AddressOfo expresiones lambda, calcule los niveles de relajación del delegado para cada argumento como se indica a continuación. Si el peor nivel de relajación del delegado (más bajo) enNes peor que el nivel de relajación de delegado más bajo enM, elimineNdel conjunto. Los niveles de relajación del delegado son los siguientes:Nivel de relajación del delegado de error : si el
AddressOfo lambda no se puede convertir al tipo delegado.Restricción de la relajación del delegado del tipo de valor devuelto o de los parámetros : si el argumento es
AddressOfo una lambda con un tipo declarado y la conversión de su tipo devuelto al tipo de valor devuelto delegado está estrechando; o si el argumento es una expresión lambda normal y la conversión de cualquiera de sus expresiones de retorno al tipo de valor devuelto delegado está estrechando, o si el argumento es una lambda asincrónica y el tipo de valor devuelto delegado esTask(Of T)y la conversión de cualquiera de sus expresiones de retorno aTes estrecha; o si el argumento es una lambda de iterador y el tipoIEnumerator(Of T)de valor devuelto delegado oIEnumerable(Of T)y la conversión de cualquiera de sus operandos de rendimiento aTes estrecha.Ampliación de la relajación del delegado para delegar sin firma : si el tipo de delegado es
System.DelegateoSystem.MultiCastDelegateSystem.Object.Quitar la relajación de los argumentos o de devolución: si el argumento es
AddressOfo una lambda con un tipo de valor devuelto declarado y el tipo delegado carece de un tipo de valor devuelto; o si el argumento es una expresión lambda con una o varias expresiones de retorno y el tipo delegado carece de un tipo de valor devuelto; o si el argumento esAddressOfo lambda sin parámetros y el tipo delegado tiene parámetros.Ampliación de la relajación del delegado del tipo de valor devuelto: si el argumento es
AddressOfo una lambda con un tipo de valor devuelto declarado, y hay una conversión de ampliación del tipo de valor devuelto al del delegado; o si el argumento es una expresión lambda normal donde la conversión de todas las expresiones de retorno al tipo de valor devuelto delegado es de ampliación o identidad con al menos un ancho; o si el argumento es una lambda asincrónica y el delegado esTask(Of T)oTasky la conversión de todas las expresiones de retorno aTObject/, respectivamente, es una ampliación o identidad con al menos una ampliación; o si el argumento es una expresión lambda de iterador y el delegado esIEnumerator(Of T)oIEnumerable(Of T)oIEnumeratoryIEnumerablela conversión de todas las expresiones de retorno aT/Objectes de ampliación o identidad con al menos una ampliación.Relajación del delegado de identidad : si el argumento es o
AddressOfuna expresión lambda que coincide exactamente con el delegado, sin ampliación ni restricción ni eliminación de parámetros o devuelve o produce. A continuación, si algunos miembros del conjunto no requieren que las conversiones de restricción sean aplicables a cualquiera de los argumentos, elimine todos los miembros que hacen. Por ejemplo:
Sub f(x As Object) End Sub Sub f(x As Short) End Sub Sub f(x As Short()) End Sub f("5") ' picks the Object overload, since String->Short is narrowing f(5) ' picks the Object overload, since Integer->Short is narrowing f({5}) ' picks the Object overload, since Integer->Short is narrowing f({}) ' a tie-breaker rule subsequent to [3] picks the Short() overloadA continuación, la eliminación se realiza en función de la restricción como se indica a continuación. (Tenga en cuenta que, si Option Strict está activado, todos los miembros que requieren restricción ya se han juzgado inaplicable (sección aplicabilidad a la lista de argumentos) y eliminados en el paso 2).
- Si algunos miembros de instancia del conjunto solo requieren conversiones de restricción en las que el tipo de expresión de argumento es
Object, elimine todos los demás miembros. - Si el conjunto contiene más de un miembro que requiere restringir solo desde
Object, la expresión de destino de invocación se reclasifica como acceso al método enlazado en tiempo de ejecución (y se proporciona un error si el tipo que contiene el grupo de métodos es una interfaz o si alguno de los miembros aplicables eran miembros de extensión). - Si hay candidatos que solo requieran restringir literales numéricos, elija el más específico entre todos los candidatos restantes por los pasos siguientes. Si el ganador solo requiere restringir los literales numéricos, se elige como resultado de la resolución de sobrecarga; de lo contrario, es un error.
Nota. La justificación de esta regla es que si un programa tiene un tipo flexible (es decir, la mayoría o todas las variables se declaran como
Object), la resolución de sobrecarga puede ser difícil cuando muchas conversiones deObjectestán estrechando. En lugar de que se produzca un error en la resolución de sobrecarga en muchas situaciones (lo que requiere una escritura fuerte de los argumentos en la llamada al método), la resolución del método sobrecargado adecuado a la llamada se aplaza hasta el tiempo de ejecución. Esto permite que la llamada de tipo flexible se realice correctamente sin conversiones adicionales. Sin embargo, un efecto secundario lamentable de esto es que realizar la llamada enlazada en tiempo de ejecución requiere convertir el destino de llamada enObject. En el caso de un valor de estructura, esto significa que el valor se debe boxear en un valor temporal. Si finalmente se llama al método intenta cambiar un campo de la estructura, este cambio se perderá una vez que el método vuelva. Las interfaces se excluyen de esta regla especial porque el enlace en tiempo de ejecución siempre se resuelve en los miembros de la clase en tiempo de ejecución o el tipo de estructura, que pueden tener nombres diferentes a los miembros de las interfaces que implementan.- Si algunos miembros de instancia del conjunto solo requieren conversiones de restricción en las que el tipo de expresión de argumento es
A continuación, si algún método de instancia permanece en el conjunto que no requiere restricción, elimine todos los métodos de extensión del conjunto. Por ejemplo:
Imports System.Runtime.CompilerServices Class C3 Sub M1(d As Integer) End Sub End Class Module C3Extensions <Extension> _ Sub M1(c3 As C3, c As Long) End Sub <Extension> _ Sub M1(c3 As C3, c As Short) End Sub End Module Module Test Sub Main() Dim c As New C3() Dim sVal As Short = 10 Dim lVal As Long = 20 ' Calls C3.M1, since C3.M1 is applicable. c.M1(sVal) ' Calls C3Extensions.M1 since C3.M1 requires a narrowing conversion c.M1(lVal) End Sub End ModuleNota. Los métodos de extensión se omiten si hay métodos de instancia aplicables para garantizar que agregar una importación (que podría traer nuevos métodos de extensión al ámbito) no provocará una llamada en un método de instancia existente para volver a enlazar a un método de extensión. Dado el amplio ámbito de algunos métodos de extensión (es decir, los definidos en interfaces o parámetros de tipo), se trata de un enfoque más seguro para enlazar a métodos de extensión.
A continuación, si, dados dos miembros del conjunto
MyN,Mes más específico ( La especificidad de sección de miembros o tipos dada una lista de argumentos) queNdada la lista de argumentos, elimineNdel conjunto. Si más de un miembro permanece en el conjunto y los miembros restantes no son igualmente específicos según la lista de argumentos, se producirá un error en tiempo de compilación.De lo contrario, dados dos miembros del conjunto y
MN, aplique las siguientes reglas de desempate, en orden:Si
Mno tiene un parámetro ParamArray, peroNsí, o si ambos lo hacen, peroMpasa menos argumentos al parámetro ParamArray queNsí, elimineNdel conjunto. Por ejemplo:Module Test Sub F(a As Object, ParamArray b As Object()) Console.WriteLine("F(Object, Object())") End Sub Sub F(a As Object, b As Object, ParamArray c As Object()) Console.WriteLine("F(Object, Object, Object())") End Sub Sub G(Optional a As Object = Nothing) Console.WriteLine("G(Object)") End Sub Sub G(ParamArray a As Object()) Console.WriteLine("G(Object())") End Sub Sub Main() F(1) F(1, 2) F(1, 2, 3) G() End Sub End ModuleEn el ejemplo anterior se genera la siguiente salida:
F(Object, Object()) F(Object, Object, Object()) F(Object, Object, Object()) G(Object)Nota. Cuando una clase declara un método con un parámetro paramarray, no es raro incluir también algunos de los formularios expandidos como métodos normales. Al hacerlo, es posible evitar la asignación de una instancia de matriz que se produce cuando se invoca una forma expandida de un método con un parámetro paramarray.
Si
Mse define en un tipo más derivado queN, elimineNdel conjunto. Por ejemplo:Class Base Sub F(Of T, U)(x As T, y As U) End Sub End Class Class Derived Inherits Base Overloads Sub F(Of T, U)(x As U, y As T) End Sub End Class Module Test Sub Main() Dim d As New Derived() ' Calls Derived.F d.F(10, 10) End Sub End ModuleEsta regla también se aplica a los tipos en los que se definen los métodos de extensión. Por ejemplo:
Imports System.Runtime.CompilerServices Class Base End Class Class Derived Inherits Base End Class Module BaseExt <Extension> _ Sub M(b As Base, x As Integer) End Sub End Module Module DerivedExt <Extension> _ Sub M(d As Derived, x As Integer) End Sub End Module Module Test Sub Main() Dim b As New Base() Dim d As New Derived() ' Calls BaseExt.M b.M(10) ' Calls DerivedExt.M d.M(10) End Sub End ModuleSi
MyNson métodos de extensión y el tipo de destino deMes una clase o estructura y el tipo de destino deNes una interfaz, elimineNdel conjunto. Por ejemplo:Imports System.Runtime.CompilerServices Interface I1 End Interface Class C1 Implements I1 End Class Module Ext1 <Extension> _ Sub M(i As I1, x As Integer) End Sub End Module Module Ext2 <Extension> _ Sub M(c As C1, y As Integer) End Sub End Module Module Test Sub Main() Dim c As New C1() ' Calls Ext2.M, because Ext1.M is hidden since it extends ' an interface. c.M(10) ' Calls Ext1.M CType(c, I1).M(10) End Sub End ModuleSi
MyNson métodos de extensión, y el tipo de destino deMyNson idénticos después de la sustitución de parámetros de tipo, y el tipo de destino de antes deMla sustitución de parámetros de tipo no contiene parámetros de tipo, pero el tipo de destino de sí tiene menos parámetros deNtipo que el tipo de destino deN, elimineNdel conjunto. Por ejemplo:Imports System.Runtime.CompilerServices Module Module1 Sub Main() Dim x As Integer = 1 x.f(1) ' Calls first "f" extension method Dim y As New Dictionary(Of Integer, Integer) y.g(1) ' Ambiguity error End Sub <Extension()> Sub f(x As Integer, z As Integer) End Sub <Extension()> Sub f(Of T)(x As T, z As T) End Sub <Extension()> Sub g(Of T)(y As Dictionary(Of T, Integer), z As T) End Sub <Extension()> Sub g(Of T)(y As Dictionary(Of T, T), z As T) End Sub End ModuleAntes de sustituir los argumentos de tipo, si
Mes menos genérico ( Genericidad de sección) queN, elimineNdel conjunto.Si
Mno es un método de extensión yNes , elimineNdel conjunto.Si
MyNson métodos de extensión yMse encontraron antesN(Colección de métodos de extensión de sección), elimineNdel conjunto. Por ejemplo:Imports System.Runtime.CompilerServices Class C1 End Class Namespace N1 Module N1C1Extensions <Extension> _ Sub M1(c As C1, x As Integer) End Sub End Module End Namespace Namespace N1.N2 Module N2C1Extensions <Extension> _ Sub M1(c As C1, y As Integer) End Sub End Module End Namespace Namespace N1.N2.N3 Module Test Sub Main() Dim x As New C1() ' Calls N2C1Extensions.M1 x.M1(10) End Sub End Module End NamespaceSi los métodos de extensión se encontraron en el mismo paso, esos métodos de extensión son ambiguos. La llamada siempre puede desambiguarse con el nombre del módulo estándar que contiene el método de extensión y llamar al método de extensión como si fuera miembro normal. Por ejemplo:
Imports System.Runtime.CompilerServices Class C1 End Class Module C1ExtA <Extension> _ Sub M(c As C1) End Sub End Module Module C1ExtB <Extension> _ Sub M(c As C1) End Sub End Module Module Main Sub Test() Dim c As New C1() C1.M() ' Ambiguous between C1ExtA.M and BExtB.M C1ExtA.M(c) ' Calls C1ExtA.M C1ExtB.M(c) ' Calls C1ExtB.M End Sub End ModuleSi
MyNambas inferencias de tipos necesarias para generar argumentos de tipo yMno requerían determinar el tipo dominante para ninguno de sus argumentos de tipo (es decir, cada uno de los argumentos de tipo inferidos a un solo tipo), peroNlo hizo, eliminóNdel conjunto.Nota. Esta regla garantiza que la resolución de sobrecargas que se realizó correctamente en versiones anteriores (donde la inferencia de varios tipos para un argumento de tipo provocaría un error), siga produciendo los mismos resultados.
Si se realiza la resolución de sobrecarga para resolver el destino de una expresión de creación de delegados a partir de una
AddressOfexpresión, y tanto el delegado comoMson funciones mientrasNse trata de una subrutina, elimineNdel conjunto. Del mismo modo, si el delegado yMson subrutinas, mientrasNque es una función, elimineNdel conjunto.Si
Mno ha usado ningún valor predeterminado de parámetro opcional en lugar de argumentos explícitos, peroNsí lo ha hecho, elimineNdel conjunto.Antes de sustituir los argumentos de tipo, si
Mtiene mayor profundidad de genérica ( Genericidad de sección) queN, elimineNdel conjunto.
De lo contrario, la llamada es ambigua y se produce un error en tiempo de compilación.
Especificidad de los miembros o tipos dada una lista de argumentos
Un miembro M se considera igualmente específico como N, dada una lista Ade argumentos , si sus firmas son iguales o si cada tipo de parámetro de M es el mismo que el tipo de parámetro correspondiente en N.
Nota. Dos miembros pueden acabar en un grupo de métodos con la misma firma debido a los métodos de extensión. Dos miembros también pueden ser igualmente específicos, pero no tienen la misma firma debido a parámetros de tipo o expansión paramarray.
Un miembro M se considera más específico que N si sus firmas son diferentes y al menos un tipo de parámetro de M es más específico que un tipo de parámetro en N, y ningún tipo de parámetro en N es más específico que un tipo de parámetro en M. Dado un par de parámetros Mj y Nj que coincide con un argumento Aj, el tipo de Mj se considera más específico que el tipo de Nj si se cumple una de las condiciones siguientes:
Existe una conversión de ampliación del tipo de
Mjal tipoNj. (Nota. Dado que los tipos de parámetros se comparan sin tener en cuenta el argumento real en este caso, la conversión de ampliación de expresiones constantes a un tipo numérico en el que se ajusta el valor no se considera en este caso).Ajes el literal0,Mjes un tipo numérico yNjes un tipo enumerado. (Nota. Esta regla es necesaria porque el literal0amplía a cualquier tipo enumerado. Dado que un tipo enumerado amplía a su tipo subyacente, esto significa que, de forma predeterminada, la resolución de sobrecargas en0sí prefiere los tipos enumerados en los tipos numéricos. Hemos recibido muchos comentarios sobre que este comportamiento era contraintuitivo).MjyNjson tipos numéricos, yMjvienen anteriores aNjen la listaByte, ,ShortUIntegerIntegerUShortSByteULongDecimalLong, .DoubleSingle(Nota. La regla sobre los tipos numéricos es útil porque los tipos numéricos firmados y sin signo de un tamaño determinado solo tienen conversiones de restricción entre ellos. La regla anterior interrumpe el empate entre los dos tipos en favor del tipo numérico más "natural". Esto es especialmente importante al realizar la resolución de sobrecargas en un tipo que amplía los tipos numéricos firmados y sin signo de un tamaño determinado, por ejemplo, un literal numérico que se ajusta a ambos).MjyNjson tipos de función de delegado y el tipo de valor devuelto deMjes más específico que el tipo de valor devuelto IfNjAjse clasifica como un método lambda, yMjoNjesSystem.Linq.Expressions.Expression(Of T), el argumento type del tipo (suponiendo que es un tipo delegado) se sustituye por el tipo que se va a comparar.Mjes idéntico al tipo deAjyNjno es . (Nota. Es interesante tener en cuenta que la regla anterior difiere ligeramente de C#, en que C# requiere que los tipos de función delegado tengan listas de parámetros idénticas antes de comparar los tipos de valor devuelto, mientras que Visual Basic no).
Genérico
Un miembro M se determina que es menos genérico que un miembro N de la siguiente manera:
- Si, para cada par de parámetros
Mjcoincidentes yNj,Mjes menor o igual queNjcon respecto a los parámetros de tipo en el método, y al menos unoMjes menos genérico con respecto a los parámetros de tipo en el método . - De lo contrario, si para cada par de parámetros
Mjcoincidentes yNj,Mjes menor o igual queNjcon respecto a los parámetros de tipo en el tipo, y al menos unoMjes menos genérico con respecto a los parámetros de tipo en el tipo, entoncesMes menos genérico queN.
Un parámetro M se considera igualmente genérico para un parámetro N si sus tipos Mt y Nt ambos hacen referencia a parámetros de tipo o ambos no hacen referencia a parámetros de tipo.
M se considera menos genérico que N si Mt no hace referencia a un parámetro de tipo y Nt sí.
Por ejemplo:
Class C1(Of T)
Sub S1(Of U)(x As U, y As T)
End Sub
Sub S1(Of U)(x As U, y As U)
End Sub
Sub S2(x As Integer, y As T)
End Sub
Sub S2(x As T, y As T)
End Sub
End Class
Module Test
Sub Main()
Dim x As C1(Of Integer) = New C1(Of Integer)
x.S1(10, 10) ' Calls S1(U, T)
x.S2(10, 10) ' Calls S2(Integer, T)
End Sub
End Module
Los parámetros de tipo de método de extensión que se han corregido durante el currying se consideran parámetros de tipo en el tipo, no los parámetros de tipo en el método . Por ejemplo:
Imports System.Runtime.CompilerServices
Module Ext1
<Extension> _
Sub M1(Of T, U)(x As T, y As U, z As U)
End Sub
End Module
Module Ext2
<Extension> _
Sub M1(Of T, U)(x As T, y As U, z As T)
End Sub
End Module
Module Test
Sub Main()
Dim i As Integer = 10
i.M1(10, 10)
End Sub
End Module
Profundidad de genérica
Se determina que un miembro M tiene mayor profundidad de genérica que un miembro N si, para cada par de parámetros Mj coincidentes y Nj, Mj tiene mayor o igual profundidad de genérico que Nj, y al menos uno Mj tiene mayor profundidad de genérica. La profundidad de la genérica se define de la siguiente manera:
Cualquier otra cosa que no sea un parámetro de tipo tiene mayor profundidad de genérica que un parámetro de tipo;
Recursivamente, un tipo construido tiene mayor profundidad de genérica que otro tipo construido (con el mismo número de argumentos de tipo) si al menos un argumento de tipo tiene mayor profundidad de genérico y ningún argumento de tipo tiene menos profundidad que el argumento de tipo correspondiente en el otro.
Un tipo de matriz tiene mayor profundidad de genérica que otro tipo de matriz (con el mismo número de dimensiones) si el tipo de elemento del primero tiene mayor profundidad de genérica que el tipo de elemento del segundo.
Por ejemplo:
Module Test
Sub f(Of T)(x As Task(Of T))
End Sub
Sub f(Of T)(x As T)
End Sub
Sub Main()
Dim x As Task(Of Integer) = Nothing
f(x) ' Calls the first overload
End Sub
End Module
Aplicabilidad a la lista de argumentos
Un método es aplicable a un conjunto de argumentos de tipo, argumentos posicionales y argumentos con nombre si el método se puede invocar mediante las listas de argumentos. Las listas de argumentos se comparan con las listas de parámetros de la siguiente manera:
- En primer lugar, coincida con cada argumento posicional para la lista de parámetros de método. Si hay más argumentos posicionales que los parámetros y el último parámetro no es paramarray, el método no es aplicable. De lo contrario, el parámetro paramarray se expande con parámetros del tipo de elemento paramarray para que coincida con el número de argumentos posicionales. Si se omite un argumento posicional que entraría en un paramarray, el método no es aplicable.
- A continuación, haga coincidir cada argumento con nombre con un parámetro con el nombre especificado. Si uno de los argumentos con nombre no coincide, coincide con un parámetro paramarray o coincide con un argumento ya coincidente con otro argumento posicional o con nombre, el método no es aplicable.
- A continuación, si se han especificado argumentos de tipo, se comparan con la lista de parámetros de tipo . Si las dos listas no tienen el mismo número de elementos, el método no es aplicable, a menos que la lista de argumentos de tipo esté vacía. Si la lista de argumentos de tipo está vacía, se usa la inferencia de tipos para intentar inferir la lista de argumentos de tipo. Si se produce un error en la inferencia de tipos, el método no es aplicable. De lo contrario, los argumentos de tipo se rellenan en el lugar de los parámetros de tipo en la firma. Si los parámetros que no se han coinciden no son opcionales, el método no es aplicable.
- Si las expresiones de argumento no se pueden convertir implícitamente en los tipos de los parámetros que coinciden, el método no es aplicable.
- Si un parámetro es ByRef y no hay una conversión implícita del tipo del parámetro al tipo del argumento, el método no es aplicable.
- Si los argumentos de tipo infringen las restricciones del método (incluidos los argumentos de tipo inferido del paso 3), el método no es aplicable. Por ejemplo:
Module Module1
Sub Main()
f(Of Integer)(New Exception)
' picks the first overload (narrowing),
' since the second overload (widening) violates constraints
End Sub
Sub f(Of T)(x As IComparable)
End Sub
Sub f(Of T As Class)(x As Object)
End Sub
End Module
Si una expresión de argumento único coincide con un parámetro paramarray y el tipo de la expresión de argumento se puede convertir tanto al tipo del parámetro paramarray como al tipo de elemento paramarray, el método se aplica tanto en sus formularios expandidos como sin expandir, con dos excepciones. Si la conversión del tipo de la expresión de argumento al tipo paramarray está estrechando, el método solo se aplica en su forma expandida. Si la expresión de argumento es el literal Nothing, el método solo es aplicable en su forma no expandida. Por ejemplo:
Module Test
Sub F(ParamArray a As Object())
Dim o As Object
For Each o In a
Console.Write(o.GetType().FullName)
Console.Write(" ")
Next o
Console.WriteLine()
End Sub
Sub Main()
Dim a As Object() = { 1, "Hello", 123.456 }
Dim o As Object = a
F(a)
F(CType(a, Object))
F(o)
F(CType(o, Object()))
End Sub
End Module
En el ejemplo anterior se genera la siguiente salida:
System.Int32 System.String System.Double
System.Object[]
System.Object[]
System.Int32 System.String System.Double
En la primera y última invocación de F, la forma normal de es aplicable porque existe una conversión de F ampliación del tipo de argumento al tipo de parámetro (ambos son de tipo Object()) y el argumento se pasa como un parámetro de valor normal. En las invocaciones segunda y tercera, la forma normal de no es aplicable porque no existe ninguna conversión de F ampliación del tipo de argumento al tipo de parámetro (las conversiones de Object a Object() son de restricción). Sin embargo, la forma expandida de F es aplicable y la invocación crea un elemento Object() uno. El único elemento de la matriz se inicializa con el valor de argumento especificado (que es una referencia a ).Object()
Pasar argumentos y seleccionar argumentos para parámetros opcionales
Si un parámetro es un parámetro de valor, la expresión de argumento coincidente debe clasificarse como un valor. El valor se convierte en el tipo del parámetro y se pasa como parámetro en tiempo de ejecución. Si el parámetro es un parámetro de referencia y la expresión de argumento coincidente se clasifica como una variable cuyo tipo es el mismo que el parámetro , se pasa una referencia a la variable como parámetro en tiempo de ejecución.
De lo contrario, si la expresión de argumento coincidente se clasifica como una variable, valor o acceso a propiedades, se asigna una variable temporal del tipo del parámetro. Antes de la invocación del método en tiempo de ejecución, la expresión de argumento se vuelve a clasificar como un valor, se convierte en el tipo del parámetro y se asigna a la variable temporal. A continuación, se pasa una referencia a la variable temporal como parámetro . Una vez evaluada la invocación del método, si la expresión de argumento se clasifica como una variable o acceso a propiedades, la variable temporal se asigna a la expresión de variable o a la expresión de acceso de propiedad. Si la expresión de acceso de propiedad no tiene ningún Set descriptor de acceso, no se realiza la asignación.
Para parámetros opcionales en los que no se ha proporcionado un argumento, el compilador elige argumentos como se describe a continuación. En todos los casos, comprueba el tipo de parámetro después de la sustitución de tipos genéricos.
Si el parámetro opcional tiene el atributo
System.Runtime.CompilerServices.CallerLineNumbery la invocación procede de una ubicación en el código fuente y un literal numérico que representa el número de línea de esa ubicación tiene una conversión intrínseca al tipo de parámetro, se usa el literal numérico. Si la invocación abarca varias líneas, la elección de la línea que se va a usar depende de la implementación.Si el parámetro opcional tiene el atributo
System.Runtime.CompilerServices.CallerFilePathy la invocación procede de una ubicación en el código fuente y un literal de cadena que representa la ruta de acceso del archivo de esa ubicación tiene una conversión intrínseca al tipo de parámetro, se usa el literal de cadena. El formato de la ruta de acceso del archivo depende de la implementación.Si el parámetro opcional tiene el atributo
System.Runtime.CompilerServices.CallerMemberNamey la invocación está dentro del cuerpo de un miembro de tipo o en un atributo aplicado a cualquier parte de ese miembro de tipo y un literal de cadena que representa ese nombre de miembro tiene una conversión intrínseca al tipo de parámetro, se usa el literal de cadena. Para las invocaciones que forman parte de descriptores de acceso de propiedad o controladores de eventos personalizados, el nombre de miembro usado es el de la propiedad o el propio evento. En el caso de las invocaciones que forman parte de un operador o constructor, se usa un nombre específico de la implementación.
Si no se aplica ninguno de los anteriores, se usa el valor predeterminado del parámetro opcional (o Nothing si no se proporciona ningún valor predeterminado). Y si se aplica más de uno de los anteriores, la elección de la que se va a usar depende de la implementación.
Los CallerLineNumber atributos y CallerFilePath son útiles para el registro.
CallerMemberName es útil para implementar INotifyPropertyChanged. Estos son ejemplos.
Sub Log(msg As String,
<CallerFilePath> Optional file As String = Nothing,
<CallerLineNumber> Optional line As Integer? = Nothing)
Console.WriteLine("{0}:{1} - {2}", file, line, msg)
End Sub
WriteOnly Property p As Integer
Set(value As Integer)
Notify(_p, value)
End Set
End Property
Private _p As Integer
Sub Notify(Of T As IEquatable(Of T))(ByRef v1 As T, v2 As T,
<CallerMemberName> Optional prop As String = Nothing)
If v1 IsNot Nothing AndAlso v1.Equals(v2) Then Return
If v1 Is Nothing AndAlso v2 Is Nothing Then Return
v1 = v2
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(prop))
End Sub
Además de los parámetros opcionales anteriores, Microsoft Visual Basic también reconoce algunos parámetros opcionales adicionales si se importan desde metadatos (es decir, desde una referencia DLL):
Al importar desde metadatos, Visual Basic también trata el parámetro
<Optional>como indicativo de que el parámetro es opcional: de esta manera es posible importar una declaración que tenga un parámetro opcional pero ningún valor predeterminado, aunque esto no se pueda expresar mediante laOptionalpalabra clave .Si el parámetro opcional tiene el atributo
Microsoft.VisualBasic.CompilerServices.OptionCompareAttributey el literal numérico 1 o 0 tiene una conversión al tipo de parámetro, el compilador usa como argumento el literal 1 siOption Compare Textestá en vigor o el literal 0 siOptional Compare Binaryestá en vigor.Si el parámetro opcional tiene el atributo
System.Runtime.CompilerServices.IDispatchConstantAttributey tiene el tipoObjecty no especifica un valor predeterminado, el compilador usa el argumentoNew System.Runtime.InteropServices.DispatchWrapper(Nothing).Si el parámetro opcional tiene el atributo
System.Runtime.CompilerServices.IUnknownConstantAttributey tiene el tipoObjecty no especifica un valor predeterminado, el compilador usa el argumentoNew System.Runtime.InteropServices.UnknownWrapper(Nothing).Si el parámetro opcional tiene el tipo
Objecty no especifica un valor predeterminado, el compilador usa el argumentoSystem.Reflection.Missing.Value.
Métodos condicionales
Si el método de destino al que hace referencia una expresión de invocación es una subrutina que no es miembro de una interfaz y si el método tiene uno o varios System.Diagnostics.ConditionalAttribute atributos, la evaluación de la expresión depende de las constantes de compilación condicionales definidas en ese punto del archivo de origen. Cada instancia del atributo especifica una cadena, que asigna un nombre a una constante de compilación condicional. Cada constante de compilación condicional se evalúa como si formase parte de una instrucción de compilación condicional. Si la constante se evalúa como True, la expresión se evalúa normalmente en tiempo de ejecución. Si la constante se evalúa como False, la expresión no se evalúa en absoluto.
Al buscar el atributo , se comprueba la declaración más derivada de un método reemplazable.
Nota. El atributo no es válido en funciones o métodos de interfaz y se omite si se especifica en cualquier tipo de método. Por lo tanto, los métodos condicionales solo aparecerán en instrucciones de invocación.
Inferencia de argumentos de tipo
Cuando se llama a un método con parámetros de tipo sin especificar argumentos de tipo, se usa la inferencia de argumentos de tipo para probar e inferir argumentos de tipo para la llamada. Esto permite usar una sintaxis más natural para llamar a un método con parámetros de tipo cuando los argumentos de tipo se pueden deducir trivialmente. Por ejemplo, dada la siguiente declaración de método:
Module Util
Function Choose(Of T)(b As Boolean, first As T, second As T) As T
If b Then
Return first
Else
Return second
End If
End Function
End Class
es posible invocar el Choose método sin especificar explícitamente un argumento de tipo:
' calls Choose(Of Integer)
Dim i As Integer = Util.Choose(True, 5, 213)
' calls Choose(Of String)
Dim s As String = Util.Choose(False, "a", "b")
A través de la inferencia de argumentos de tipo, los argumentos Integer de tipo y String se determinan de los argumentos al método .
La inferencia de argumentos de tipo se produce antes de que se realice la reclasificación de expresiones en métodos lambda o punteros de método en la lista de argumentos, ya que la reclasificación de esos dos tipos de expresiones puede requerir que se conozca el tipo del parámetro. Dado un conjunto de argumentos A1,...,An, un conjunto de parámetros P1,...,Pn coincidentes y un conjunto de parámetros T1,...,Tnde tipo de método , las dependencias entre los argumentos y los parámetros de tipo de método se recopilan primero de la siguiente manera:
Si
Anes elNothingliteral, no se generan dependencias.Si
Anes un método lambda y el tipo dePnes un tipo delegado construido oSystem.Linq.Expressions.Expression(Of T), dondeTes un tipo delegado construido,Si el tipo de un parámetro de método lambda se deducirá del tipo del parámetro
Pncorrespondiente y el tipo del parámetro depende de un parámetroTnde tipo de método , entoncesAntiene una dependencia deTn.Si se especifica el tipo de un parámetro de método lambda y el tipo del parámetro
Pncorrespondiente depende de un parámetroTnde tipo de método , entoncesTntiene una dependencia deAn.Si el tipo de valor devuelto de depende de
Pnun parámetroTnde tipo de método , tieneTnuna dependencia deAn.Si
Anes un puntero de método y el tipo dePnes un tipo delegado construido,Si el tipo de valor devuelto de depende de
Pnun parámetroTnde tipo de método , tieneTnuna dependencia deAn.Si
Pnes un tipo construido y el tipo de depende dePnun parámetroTnde tipo de método , tieneTnuna dependencia deAn.De lo contrario, no se genera ninguna dependencia.
Después de recopilar dependencias, se eliminan los argumentos que no tienen dependencias. Si algún parámetro de tipo de método no tiene dependencias salientes (es decir, el parámetro de tipo de método no depende de un argumento), se produce un error en la inferencia de tipos. De lo contrario, los argumentos restantes y los parámetros de tipo de método se agrupan en componentes fuertemente conectados. Un componente fuertemente conectado es un conjunto de argumentos y parámetros de tipo de método, donde cualquier elemento del componente es accesible a través de dependencias de otros elementos.
Los componentes fuertemente conectados se ordenan y procesan de forma topológica en orden topológico:
Si el componente fuertemente tipado contiene solo un elemento,
Si el elemento ya se ha marcado como completado, omitalo.
Si el elemento es un argumento, agregue sugerencias de tipo del argumento a los parámetros de tipo de método que dependen de él y marque el elemento como completo. Si el argumento es un método lambda con parámetros que todavía necesitan tipos inferidos, infiere
Objectpara los tipos de esos parámetros.Si el elemento es un parámetro de tipo de método, infiere el parámetro de tipo de método para que sea el tipo dominante entre las sugerencias de tipo de argumento y marque el elemento como completo. Si una sugerencia de tipo tiene una restricción de elemento de matriz en ella, solo se consideran conversiones válidas entre matrices del tipo especificado (es decir, conversiones de matriz intrínseca y covariante). Si una sugerencia de tipo tiene una restricción de argumento genérico en ella, solo se tienen en cuenta las conversiones de identidad. Si no se puede elegir ningún tipo dominante, se produce un error en la inferencia. Si algún tipo de argumento de método lambda depende de este parámetro de tipo de método, el tipo se propaga al método lambda.
Si el componente fuertemente tipado contiene más de un elemento, el componente contiene un ciclo.
Para cada parámetro de tipo de método que sea un elemento del componente, si el parámetro de tipo de método depende de un argumento que no está marcado como completado, convierta esa dependencia en una aserción que se comprobará al final del proceso de inferencia.
Reinicie el proceso de inferencia en el momento en el que se determinaron los componentes fuertemente tipados.
Si la inferencia de tipos se realiza correctamente para todos los parámetros de tipo de método, se comprueban las dependencias que se cambiaron en aserciones. Una aserción se realiza correctamente si el tipo del argumento se puede convertir implícitamente al tipo inferido del parámetro de tipo de método. Si se produce un error en una aserción, se produce un error en la inferencia de argumentos de tipo.
Dado un tipo Ta de argumento para un argumento A y un tipo Tp de parámetro para un parámetro P, las sugerencias de tipo se generan de la siguiente manera:
Si
Tpno implica ningún parámetro de tipo de método, no se genera ninguna sugerencia.Si
TpyTason tipos de matriz del mismo rango, reemplaceTayTppor los tipos de elemento deTay reinicieTpeste proceso con una restricción de elemento de matriz.Si
Tpes un parámetro de tipo de método,Tase agrega como sugerencia de tipo con la restricción actual, si existe.Si
Aes un método lambda yTpes un tipo delegado construido oSystem.Linq.Expressions.Expression(Of T), dondeTes un tipo delegado construido, para cada tipoTLde parámetro de método lambda y el tipoTDde parámetro delegado correspondiente , reemplace porTaTLyTpporTDy reinicie el proceso sin ninguna restricción. A continuación, reemplace porTael tipo de valor devuelto del método lambda y:- si
Aes un método lambda normal, reemplace porTpel tipo de valor devuelto del tipo delegado; - si
Aes un método lambda asincrónico y el tipo de valor devuelto del tipo delegado tiene formaTask(Of T)para algunosT, reemplaceTppor eseT; - si
Aes un método lambda de iterador y el tipo de valor devuelto del tipo delegado tiene formaIEnumerator(Of T)oIEnumerable(Of T)para algunosT, reemplace porTpeseT. - A continuación, reinicie el proceso sin restricciones.
- si
Si
Aes un puntero de método yTpes un tipo delegado construido, use los tipos de parámetro deTppara determinar qué método apunta más aplicable aTp. Si hay un método más aplicable, reemplaceTapor el tipo de valor devuelto del método yTppor el tipo de valor devuelto del tipo delegado y reinicie el proceso sin restricciones.De lo contrario,
Tpdebe ser un tipo construido. DadoTG, el tipo genérico deTp,Si
TaesTG, hereda deTGo implementa el tipoTGexactamente una vez, para cada argumentoTaxde tipo coincidente deTayTpxdesdeTp, reemplace porTaTaxy porTpxyTpreinicie el proceso con una restricción de argumento genérico.De lo contrario, se produce un error en la inferencia de tipos para el método genérico.
El éxito de la inferencia de tipos no garantiza, en sí mismo, que el método sea aplicable.
Visual Basic language spec