Řešení přetížené metody

V praxi jsou pravidla pro určení rozlišení přetížení určena k nalezení přetížení, které je "nejblíže" k zadaným skutečným argumentům. Pokud existuje metoda, jejíž typy parametrů odpovídají typům argumentů, je tato metoda zřejmě nejblíže. Pokud jsou všechny jeho typy parametrů užší než (nebo stejné jako) typy parametrů druhé metody, je tato metoda blíže než jiná. Pokud parametry žádné metody nejsou užší než ostatní, neexistuje způsob, jak určit, která metoda je blíže argumentům.

Poznámka. Řešení přetížení nebere v úvahu očekávaný návratový typ metody.

Všimněte si také, že vzhledem k pojmenované syntaxi parametru nemusí být řazení skutečných a formálních parametrů stejné.

Vzhledem ke skupině metod se nejužitečnější metoda ve skupině pro seznam argumentů určuje pomocí následujícího postupu. Pokud po použití konkrétního kroku nezůstanou v sadě žádní členové, dojde k chybě v době kompilace. Pokud v sadě zůstane jenom jeden člen, je tento člen nejužitevějším členem. Postupujte takto:

  1. Za prvé, pokud nebyly zadány žádné argumenty typu, použijte odvození typu u všech metod, které mají parametry typu. Pokud je odvození typu pro metodu úspěšné, použijí se pro danou konkrétní metodu argumenty odvozeného typu. Pokud odvození typu pro metodu selže, pak je tato metoda vyloučena ze sady.

  2. V dalším kroku vyloučíte všechny členy ze sady, které jsou nepřístupné nebo nelze použít (seznam použitelnosti argumentů oddílu) v seznamu argumentů.

  3. Pokud jsou AddressOf jeden nebo více argumentů výrazy nebo výrazy lambda, vypočítejte úrovně uvolnění delegáta pro každý argument, jak je uvedeno níže. Pokud nejhorší (nejnižší) úroveň uvolnění delegáta je N horší než nejnižší úroveň uvolnění delegáta v M, pak eliminujte N ze sady. Úrovně uvolnění delegáta jsou následující:

    1. Úroveň uvolnění delegáta chyby – pokud AddressOf není možné převést na typ delegáta nebo lambda.

    2. Zúžení delegovaného uvolnění návratového typu nebo parametrů – pokud je AddressOf argument nebo lambda s deklarovaným typem a převod z návratového typu delegáta na návratový typ delegáta se zužuje; nebo pokud je argument regulární lambda a převod z některého z jeho návratových výrazů na návratový typ delegáta se zúží, nebo je-li argument asynchronní lambda a návratový typ delegáta je Task(Of T) a převod z některého z jeho návratových výrazů na T zúžení; nebo pokud je argument lambda iterátoru a delegující návratový typ IEnumerator(Of T) nebo IEnumerable(Of T) a převod z některého z jeho výnosných operandů na T zúžení.

    3. Rozšíření uvolnění delegáta na delegáta bez podpisu - pokud je typ delegáta System.Delegate nebo System.ObjectSystem.MultiCastDelegate nebo .

    4. Uvolnění návratu nebo argumentů delegování delegáta – pokud je AddressOf argument nebo lambda s deklarovaným návratovým typem a typu delegáta chybí návratový typ, nebo pokud je argument lambda s jedním nebo více návratovými výrazy a typ delegáta nemá návratový typ; nebo pokud je AddressOf argument nebo lambda bez parametrů a typ delegáta má parametry.

    5. Rozšíření delegovaného uvolnění návratového typu - pokud je AddressOf argument nebo lambda s deklarovaným návratovým typem, a existuje rozšiřující převod z jeho návratového typu na delegáta; nebo je-li argument regulární lambda, kde převod ze všech návratových výrazů na návratový typ delegáta rozšiřuje nebo identita s alespoň jedním rozšířením; nebo pokud je argument asynchronní lambda a delegát je Task(Of T) nebo Task a převod ze všech vrácených výrazů na TObject/v uvedeném pořadí je rozšiřující nebo identita s alespoň jedním rozšířením; nebo pokud je argumentem lambda iterátor a delegát je IEnumerator(Of T) nebo IEnumerable(Of T)IEnumerator nebo IEnumerable a převod ze všech vrácených výrazů na T/Object rozšíření nebo identitu s alespoň jedním rozšířením.

    6. Uvolnění delegáta identity – pokud je argument nebo AddressOf lambda, který přesně odpovídá delegátovi, bez rozšíření nebo zužování nebo vyřazení parametrů nebo vrácení nebo výnosu. Pokud některé členy sady nevyžadují zužující převody, aby byly použitelné pro některý z argumentů, odstraňte všechny členy, které dělají. Například:

    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() overload
    
    
  4. Dále se odstranění provádí na základě zužování následujícím způsobem. (Všimněte si, že pokud je možnost Strict zapnutá, pak všichni členové, kteří vyžadují zúžení, již byli vyhodnoceni jako neaplikovatelné (oddíl Použitelnost seznamu argumentů) a odebráni krokem 2.)

    1. Pokud některé členy instance sady vyžadují pouze zúžení převodů, kde je Objecttyp výrazu argumentu , odstraňte všechny ostatní členy.
    2. Pokud sada obsahuje více než jeden člen, který vyžaduje zúžení pouze od Object, pak je vyvolání cílového výrazu přetříděn jako přístup metody s pozdní vazbou (a pokud typ obsahující skupinu metod je rozhraní, nebo pokud některý z příslušných členů byl členy rozšíření).
    3. Pokud existují kandidáti, kteří vyžadují pouze zužování číselných literálů, zvolte nejpřesnější ze všech zbývajících kandidátů pomocí následujícího postupu. Pokud vítěz vyžaduje pouze zúžení z číselných literálů, je vybrán jako výsledek rozlišení přetížení; jinak se jedná o chybu.

    Poznámka. Odůvodněním tohoto pravidla je, že pokud je program volně typovaný (tj. většina nebo všechny proměnné jsou deklarovány jako Object), rozlišení přetížení může být obtížné, pokud je mnoho převodů zužující Object . Místo toho, aby řešení přetížení selhalo v mnoha situacích (vyžaduje silné psaní argumentů volání metody), rozlišení příslušné přetížené metody volání je odloženo do doby běhu. To umožňuje, aby volání volně zadaného typu bylo úspěšné bez dalších přetypování. Nešťastným vedlejším účinkem je však to, že provedení pozdního volání vyžaduje přetypování cíle volání na Object. V případě hodnoty struktury to znamená, že hodnota musí být vložena do dočasného rámečku. Pokud se metoda nakonec zavolá pokusí změnit pole struktury, tato změna bude ztracena, jakmile metoda vrátí. Rozhraní jsou z tohoto speciálního pravidla vyloučena, protože pozdní vazby se vždy překládají proti členům třídy modulu runtime nebo typu struktury, které mohou mít jiné názvy než členové rozhraní, která implementují.

  5. Pokud některé metody instance zůstanou v sadě, které nevyžadují zúžení, odstraňte všechny rozšiřující metody ze sady. Například:

    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 Module
    

    Poznámka. Metody rozšíření se ignorují, pokud existují vhodné metody instance, které zaručují, že přidání importu (které by mohly přinést nové rozšiřující metody do oboru) nezpůsobí volání existující metody instance, aby se znovu svážela s rozšiřující metodou. Vzhledem k širokému rozsahu některých rozšiřujících metod (tj. metod definovaných na rozhraních a/nebo parametrech typu) je to bezpečnější přístup k vazbám na rozšiřující metody.

  6. V dalším kroku, pokud je při zadání libovolných dvou členů množiny M a Nje Mkonkrétnější ( specifika oddílů členů/typů zadaných seznamem argumentů), než N je uveden seznam argumentů, odstraňte N ze sady. Pokud v sadě zůstává více než jeden člen a zbývající členy nejsou stejně specifické vzhledem k seznamu argumentů, výsledkem chyby v době kompilace.

  7. Jinak platí, že pokud jsou nastaveny jakékoli dva členy sady, M a Nv uvedeném pořadí použijte následující pravidla pro svázání:

    1. Pokud M nemá parametr ParamArray, ale N dělá, nebo pokud obojí dělá, ale M předává méně argumentů do parametru ParamArray, než N dělá, odstraňte N ze sady. Například:

      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 Module
      

      Výše uvedený příklad vytvoří následující výstup:

      F(Object, Object())
      F(Object, Object, Object())
      F(Object, Object, Object())
      G(Object)
      

      Poznámka. Když třída deklaruje metodu s parametrem paramarray, není neobvyklé zahrnout některé rozšířené formuláře jako běžné metody. Tímto způsobem je možné zabránit přidělení instance pole, ke kterému dochází při vyvolání rozšířené formy metody s parametrem paramarray.

    2. Pokud M je definován ve více odvozených typech než N, odstraňte N ze sady. Například:

      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 Module
      

      Toto pravidlo platí také pro typy, na které jsou definovány metody rozšíření. Například:

      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 Module
      
    3. Pokud M a N jsou rozšiřující metody a cílový typ M je třída nebo struktura a cílový typ N je rozhraní, odstraňte N ze sady. Například:

      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 Module
      
    4. Pokud M a N jsou rozšiřující metody a cílový typ M a N jsou identické po nahrazení parametru typu a cílový typ před nahrazením parametru M typu neobsahuje parametry typu, ale cílový typ N dělá, pak má méně parametrů typu než cílový typ N, eliminovat N ze sady. Například:

      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 Module
      
    5. Před nahrazením argumentů typu, pokud M je méně obecný ( generická část) než N, odstraňte N ze sady.

    6. Pokud M není metoda rozšíření a N je, odstraňte N ze sady.

    7. Pokud M a N jsou rozšiřující metody a M byly nalezeny před N (Section Extension Method Collection), odstraňte N ze sady. Například:

      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 Namespace
      

      Pokud byly metody rozšíření nalezeny ve stejném kroku, jsou tyto metody rozšíření nejednoznačné. Volání může být vždy nejednoznačné pomocí názvu standardního modulu obsahujícího rozšiřující metodu a volání metody rozšíření, jako by to byl běžný člen. Například:

      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 Module
      
    8. Pokud M i N oba požadované typy odvozují argumenty typu a M nevyžadují určení dominantního typu pro některý z argumentů typu (tj. každý argument typu odvozený na jeden typ), ale N vyloučil ze N sady.

      Poznámka. Toto pravidlo zajišťuje, že řešení přetížení, které bylo úspěšné v předchozích verzích (kde odvození více typů argumentu typu způsobí chybu), bude pokračovat ve stejných výsledcích.

    9. Pokud se provádí řešení přetížení k vyřešení cíle výrazu pro vytvoření delegáta z AddressOf výrazu, a delegát a M jsou funkce, zatímco N je podprogram, odstraňte N ze sady. Podobně platí, že pokud delegát a M jsou podprogramy, zatímco N je funkce, eliminujte N ze sady.

    10. Pokud M jste místo explicitních argumentů nepoužili žádné volitelné výchozí hodnoty parametrů, ale N vyloučili N jste je ze sady.

    11. Před nahrazením argumentů typu, pokud Mvětší hloubku genericity ( Genericity oddílu) než N, odstraňte N ze sady.

  8. V opačném případě je volání nejednoznačné a dojde k chybě v době kompilace.

Specifika členů/typů zadaných seznamem argumentů

Člen M je považován za stejně specifický jako N, vzhledem k argument-list A, pokud jsou jejich podpisy stejné nebo pokud každý typ parametru M je stejný jako odpovídající typ parametru v N.

Poznámka. Dva členové můžou skončit ve skupině metod se stejným podpisem kvůli rozšiřujícím metodám. Dva členy mohou být také stejně specifické, ale nemají stejný podpis kvůli parametrům typu nebo rozšíření paramarray.

Člen M je považován za konkrétnější , než N pokud jsou jejich podpisy odlišné a nejméně jeden typ M parametru je konkrétnější než typ parametru v Na žádný typ N parametru není konkrétnější než typ parametru v M. Vzhledem k páru parametrů Mj , Nj který odpovídá argumentu Aj, typ Mj je považován za konkrétnější než typ Nj , pokud je splněna jedna z následujících podmínek:

  • Existuje rozšiřující převod z typu Mj na typ Nj. (Poznámka: Vzhledem k tomu, že se typy parametrů porovnávají bez ohledu na skutečný argument v tomto případě, rozšíření převodu z konstantních výrazů na číselný typ, do kterého hodnota zapadá, se v tomto případě nepovažuje.)

  • Aj je literál 0, Mj je číselný typ a Nj je výčtový typ. (Poznámka: Toto pravidlo je nezbytné, protože literál 0 se rozšiřuje na jakýkoli výčtový typ. Vzhledem k tomu, že výčtový typ se rozšiřuje na jeho základní typ, znamená to, že rozlišení 0 přetížení bude ve výchozím nastavení upřednostňovat výčtové typy než číselné typy. Obdrželi jsme spoustu zpětné vazby, že toto chování bylo neintuitivní.)

  • Mja Nj jsou oba číselné typy a Mj jsou dřívější než Nj v seznamu Byte, SByte, , Short, UShort, Integer, UInteger, Long, ULong, DecimalSingle, . Double (Poznámka: Pravidlo o číselných typech je užitečné, protože znaménka a nepodepsané číselné typy určité velikosti mají pouze zužující převody mezi nimi. Výše uvedené pravidlo rozdělí vazby mezi těmito dvěma typy ve prospěch "přirozeného" číselného typu. To je zvlášť důležité, když provádíte rozlišení přetížení u typu, který rozšiřuje jak znaménka, tak i nepodepsané číselné typy konkrétní velikosti, například číselný literál, který se vejde do obou typů.)

  • Mj a Nj jsou typy funkcí delegáta a návratový Mj typ je konkrétnější než návratový Nj typ If Aj je klasifikovaný jako metoda lambda a Mj nebo Nj je System.Linq.Expressions.Expression(Of T), pak typ argumentu typu (za předpokladu, že se jedná o typ delegáta) se nahradí porovnávaným typem.

  • Mj je identický s typem Aj, a Nj není. (Poznámka: Je zajímavé si uvědomit, že předchozí pravidlo se mírně liší od jazyka C#, v tom jazyce C# vyžaduje, aby typy funkcí delegáta měly před porovnáním návratových typů identické seznamy parametrů, zatímco Visual Basic ne.)

Obecná úroveň

M Člen je určen jako méně obecný než člen N následujícím způsobem:

  1. Pokud je pro každou dvojici odpovídajících parametrů Mj menší MjNjnebo stejně obecný než Nj u parametrů typu v metodě a nejméně jeden Mj je méně obecný s ohledem na parametry typu v metodě.
  2. V opačném případě, pokud pro každou dvojici odpovídajících parametrů a , je menší nebo stejně obecný než Nj s ohledem na typ parametry typu, a alespoň jeden Mj je méně obecný s ohledem na parametry typu typu, pak M je méně obecný než N. MjNjMj

M Parametr je považován za stejně obecný pro parametrN, pokud jejich typy Mt a Nt oba odkazují na parametry typu nebo oba neodkazují na parametry typu. M je považován za méně obecný, než N pokud Mt neodkazuje na parametr typu a Nt ne.

Například:

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

Parametry typu rozšiřující metody, které byly opraveny během kariování, se považují za parametry typu typu, nikoli parametry typu metody. Například:

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

Hloubka genericity

M Člen je určen, aby měl větší hloubku genericity než členN, pokud, pro každou dvojici shodných parametrů Mj a Nj, Mj má větší nebo stejnou hloubku genericity než Nja alespoň jeden Mj je větší hloubkou genericity. Hloubka genericity je definována takto:

  • Cokoli jiného než parametr typu má větší hloubku genericity než parametr typu;

  • Rekurzivně má vytvořený typ větší hloubku genericity než jiný konstruovaný typ (se stejným počtem argumentů typu), pokud alespoň jeden argument typu má větší hloubku genericity a žádný argument typu nemá menší hloubku než odpovídající argument typu v druhém argumentu.

  • Typ pole má větší hloubku genericity než jiný typ pole (se stejným počtem dimenzí), pokud typ prvku prvního má větší hloubku genericity než typ prvku druhého.

Například:

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

Použitelnost seznamu argumentů

Metoda je použitelná pro sadu argumentů typu, pozičních argumentů a pojmenovaných argumentů, pokud lze metodu vyvolat pomocí seznamů argumentů. Seznamy argumentů se shodují se seznamy parametrů následujícím způsobem:

  1. Nejprve se shodujte s jednotlivými pozičními argumenty v seznamu parametrů metody. Pokud existuje více pozičních argumentů než parametrů a poslední parametr není paramarray, metoda není použitelná. V opačném případě je parametr paramarray rozšířen o parametry typu elementu paramarray tak, aby odpovídaly počtu pozičních argumentů. Pokud je poziční argument vynechán, který by šel do paramarray, metoda není použitelná.
  2. Dále se shodujte s každým pojmenovaným argumentem s parametrem s daným názvem. Pokud se některý z pojmenovaných argumentů neshoduje, odpovídá parametru paramarray nebo odpovídá argumentu, který je již shodný s jiným pozičním nebo pojmenovaným argumentem, metoda se nepoužije.
  3. Dále, pokud byly zadány argumenty typu, jsou porovnána se seznamem parametrů typu . Pokud dva seznamy nemají stejný počet prvků, metoda není použitelná, pokud seznam argumentů typu není prázdný. Pokud je seznam argumentů typu prázdný, použije se k vyzkoušení a odvození seznamu argumentů typu. Pokud se odvozování typu nezdaří, metoda se nedá použít. V opačném případě jsou argumenty typu vyplněny místo parametrů typu v podpisu. Pokud parametry, které nebyly spárovány, nejsou volitelné, metoda není použitelná.
  4. Pokud výrazy argumentu nejsou implicitně konvertibilní na typy parametrů, které odpovídají, pak metoda není použitelná.
  5. Pokud je parametr ByRef a neexistuje implicitní převod z typu parametru na typ argumentu, pak metoda není použitelná.
  6. Pokud argumenty typu porušují omezení metody (včetně odvozených argumentů typu z kroku 3), metoda není použitelná. Například:
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

Pokud výraz s jedním argumentem odpovídá parametru paramarray a typ výrazu argumentu je převoditelný na typ parametru paramarray i typ elementu paramarray, je metoda použitelná ve svých rozbalených i nevyexpandovaných formulářích se dvěma výjimkami. Pokud je převod z typu výrazu argumentu na typ paramarray zužující, je metoda použitelná pouze ve své rozšířené podobě. Pokud je výraz argumentu literál Nothing, pak metoda je použitelná pouze ve své nevyexpandované podobě. Například:

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

Výše uvedený příklad vytvoří následující výstup:

System.Int32 System.String System.Double
System.Object[]
System.Object[]
System.Int32 System.String System.Double

V prvním a posledním vyvolání F, normální forma F je použitelná, protože rozšiřující převod existuje z typu argumentu na typ parametru (oba jsou typu Object()) a argument se předává jako normální parametr hodnoty. Ve druhém a třetím vyvolání není normální forma F použitelná, protože neexistuje rozšiřující převod z typu argumentu na typ parametru (převody z Object na Object() zúžení). Rozšířená forma F je však použitelná a vyvolání vytvoří jeden prvek Object() . Jeden prvek pole je inicializován s danou hodnotou argumentu (což je samotný odkaz na ).Object()

Předávání argumentů a výběr argumentů pro volitelné parametry

Pokud je parametrem hodnota, musí být odpovídající výraz argumentu klasifikován jako hodnota. Hodnota se převede na typ parametru a předá se jako parametr za běhu. Pokud je parametr referenčním parametrem a odpovídající výraz argumentu je klasifikován jako proměnná, jejíž typ je stejný jako parametr, pak je odkaz na proměnnou předán jako parametr za běhu.

V opačném případě, pokud je odpovídající výraz argumentu klasifikován jako proměnná, hodnota nebo přístup k vlastnosti, je přidělena dočasná proměnná typu parametru. Před vyvoláním metody za běhu je výraz argumentu přetříděn jako hodnota, převeden na typ parametru a přiřazen k dočasné proměnné. Potom se jako parametr předá odkaz na dočasnou proměnnou. Po vyhodnocení vyvolání metody je výraz argumentu klasifikován jako proměnná nebo přístup k vlastnosti, je dočasná proměnná přiřazena k výrazu proměnné nebo výrazu přístupu k vlastnosti. Pokud přístupový výraz vlastnosti nemá žádné Set přístupové objekty, přiřazení se neprovede.

Pro volitelné parametry, ve kterých nebyl argument zadán, kompilátor vybere argumenty, jak je popsáno níže. Ve všech případech testuje typ parametru po nahrazení obecného typu.

  • Pokud volitelný parametr má atribut System.Runtime.CompilerServices.CallerLineNumbera vyvolání je z umístění ve zdrojovém kódu a číselný literál představující číslo řádku daného umístění má vnitřní převod na typ parametru, použije se číselný literál. Pokud vyvolání zahrnuje více řádků, pak výběr řádku, který se má použít, je závislý na implementaci.

  • Pokud volitelný parametr má atribut System.Runtime.CompilerServices.CallerFilePatha vyvolání je z umístění ve zdrojovém kódu a řetězcový literál představující cestu k souboru umístění má vnitřní převod na typ parametru, použije se řetězcový literál. Formát cesty k souboru je závislý na implementaci.

  • Pokud volitelný parametr má atribut System.Runtime.CompilerServices.CallerMemberNamea vyvolání je v těle člena typu nebo v atributu použitém pro libovolnou část tohoto členu typu a řetězcový literál představující tento název členu má vnitřní převod na typ parametru, použije se řetězcový literál. Pro vyvolání, které jsou součástí přístupových objektů vlastností nebo vlastních obslužných rutin událostí, pak použitý název členu je název vlastnosti nebo samotné události. Pro vyvolání, které jsou součástí operátoru nebo konstruktoru, se použije název specifický pro implementaci.

Pokud žádná z výše uvedených možností neplatí, použije se výchozí hodnota volitelného parametru (nebo Nothing pokud není zadána žádná výchozí hodnota). A pokud platí více než jedna z výše uvedených možností, pak volba, kterou použít, je závislá na implementaci.

Atributy CallerLineNumber a CallerFilePath atributy jsou užitečné pro protokolování. To CallerMemberName je užitečné pro implementaci INotifyPropertyChanged. Tady jsou příklady.

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

Kromě výše uvedených volitelných parametrů microsoft Visual Basic rozpozná také některé další volitelné parametry, pokud jsou importovány z metadat (tj. z odkazu na knihovnu DLL):

  • Při importu z metadat používá Visual Basic také parametr <Optional> jako indikující, že parametr je volitelný: tímto způsobem je možné importovat deklaraci, která má volitelný parametr, ale žádnou výchozí hodnotu, i když se nedá vyjádřit pomocí klíčového Optional slova.

  • Pokud má volitelný parametr atribut Microsoft.VisualBasic.CompilerServices.OptionCompareAttributea číselný literál 1 nebo 0 má převod na typ parametru, kompilátor použije jako argument literál 1, pokud Option Compare Text je v platnosti, nebo literál 0, pokud Optional Compare Binary je v platnosti.

  • Pokud volitelný parametr má atribut System.Runtime.CompilerServices.IDispatchConstantAttributea má typ Objecta nezadá výchozí hodnotu, kompilátor použije argument New System.Runtime.InteropServices.DispatchWrapper(Nothing).

  • Pokud volitelný parametr má atribut System.Runtime.CompilerServices.IUnknownConstantAttributea má typ Objecta nezadá výchozí hodnotu, kompilátor použije argument New System.Runtime.InteropServices.UnknownWrapper(Nothing).

  • Pokud volitelný parametr má typ Objecta nezadá výchozí hodnotu, kompilátor použije argument System.Reflection.Missing.Value.

Podmíněné metody

Pokud cílová metoda, na kterou výraz vyvolání odkazuje, je podprogram, který není členem rozhraní a pokud má metoda jeden nebo více System.Diagnostics.ConditionalAttribute atributů, vyhodnocení výrazu závisí na konstantách podmíněné kompilace definované v tomto okamžiku ve zdrojovém souboru. Každá instance atributu určuje řetězec, který pojmenuje konstantu podmíněné kompilace. Každá konstanta podmíněné kompilace se vyhodnotí jako součást příkazu podmíněné kompilace. Pokud se konstanta vyhodnotí jako True, výraz se vyhodnotí normálně za běhu. Pokud se konstanta vyhodnotí jako False, výraz se vůbec nevyhodnotí.

Při hledání atributu je kontrolována nejvíce odvozená deklarace přepisovatelné metody.

Poznámka. Atribut není platný pro funkce nebo metody rozhraní a je ignorován, pokud je zadán u některého typu metody. Podmíněné metody se tedy zobrazí pouze ve vyvolání příkazů.

Odvození argumentu typu

Pokud je volána metoda s parametry typu bez zadání argumentů typu, typ argument odvození se používá k pokusu a odvození argumentů typu pro volání. To umožňuje použití přirozenější syntaxe pro volání metody s parametry typu, když argumenty typu lze triviálně odvodit. Například s ohledem na následující deklaraci metody:

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

Metodu Choose je možné vyvolat bez explicitního zadání argumentu typu:

' 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") 

Prostřednictvím odvození argumentu typu jsou argumenty Integer typu a String jsou určeny z argumentů do metody.

Odvození argumentu typu nastane před provedením přetřídění výrazu u metod lambda nebo ukazatelů metody v seznamu argumentů, protože změna klasifikace těchto dvou druhů výrazů může vyžadovat, aby byl typ parametru znám. Vzhledem k sadě argumentů A1,...,An, sada shodných parametrů P1,...,Pn a sada parametrů T1,...,Tntypu metody , závislosti mezi argumenty a parametry typu metody jsou nejprve shromažďovány následujícím způsobem:

  • Pokud An je literál Nothing , nevygenerují se žádné závislosti.

  • Pokud An je metoda lambda a typ Pn je konstruovaný typ delegáta nebo System.Linq.Expressions.Expression(Of T), kde T je konstruovaný typ delegáta,

  • Pokud typ parametru metody lambda bude odvozen z typu odpovídajícího parametru Pna typ parametru závisí na parametru Tntypu metody , pak An má závislost na Tn.

  • Pokud je zadán typ parametru metody lambda a typ odpovídajícího parametru Pn závisí na parametru Tntypu metody , pak Tn má závislost na An.

  • Pokud návratový Pn typ závisí na parametru Tntypu metody , pak Tn má závislost na An.

  • Pokud An je ukazatel metody a typ Pn je konstruovaný typ delegáta,

  • Pokud návratový Pn typ závisí na parametru Tntypu metody , pak Tn má závislost na An.

  • Pokud Pn je vytvořený typ a typ Pn závisí na parametru Tntypu metody , pak Tn má závislost na An.

  • Jinak se nevygeneruje žádná závislost.

Po shromáždění závislostí se eliminují všechny argumenty, které nemají žádné závislosti. Pokud některé parametry typu metody nemají žádné odchozí závislosti (tj. parametr typu metody nezávisí na argumentu), odvození typu selže. V opačném případě se zbývající argumenty a parametry typu metody seskupí do silně propojených komponent. Silně propojená komponenta je sada argumentů a parametrů typu metody, kde jakýkoli prvek v komponentě je dosažitelný prostřednictvím závislostí na jiných prvcích.

Silně propojené komponenty jsou pak topologické a zpracovávané v topologickém pořadí:

  • Pokud součást silného typu obsahuje pouze jeden prvek,

    • Pokud už byl prvek označený jako dokončený, přeskočte ho.

    • Pokud je element argumentem, přidejte z argumentu do parametrů typu metody, které na něm závisí, a označte prvek jako dokončený. Pokud je argument metodou lambda s parametry, které stále potřebují odvozené typy, odvozujte Object je pro typy těchto parametrů.

    • Pokud je element parametrem typu metody, odvozujte parametr typu metody jako dominantní typ mezi rady typu argumentu a označte prvek jako dokončený. Pokud má nápověda typu omezení prvku pole, pak se považují pouze převody platné mezi poli daného typu (tj. kovariantní a vnitřní převody polí). Pokud je u nápovědy typu omezení obecného argumentu, zvažují se pouze převody identit. Pokud nelze zvolit žádný dominantní typ, odvození selže. Pokud některé typy argumentů metody lambda závisí na tomto parametru typu metody, typ se rozšíří do metody lambda.

  • Pokud součást silného typu obsahuje více než jeden prvek, komponenta obsahuje cyklus.

    • Pro každý parametr typu metody, který je prvkem v komponentě, pokud parametr typu metody závisí na argumentu, který není označen jako dokončený, převeďte tuto závislost na kontrolní výraz, který bude zkontrolován na konci procesu odvozování.

    • Restartujte proces odvození v okamžiku určení komponent silného typu.

Pokud odvození typu proběhne úspěšně pro všechny parametry typu metody, zkontrolují se všechny závislosti, které byly změněny na kontrolní výrazy. Kontrolní výraz je úspěšný, pokud je typ argumentu implicitně konvertibilní na odvozený typ parametru typu metody. Pokud kontrolní výraz selže, funkce odvození argumentu typu selže.

Při zadání typu Ta argumentu pro argument A a typ Tp parametru pro parametr Pse vygenerují rady typu následujícím způsobem:

  • Pokud Tp nezahrnuje žádné parametry typu metody, nebudou generovány žádné rady.

  • Pokud Tp a Ta jsou typy polí stejného pořadí, nahraďte Ta a Tp nahraďte typy Ta prvků a Tp restartujte tento proces omezením prvku pole.

  • Pokud Tp je parametr typu metody, přidá Ta se jako tip typu s aktuálním omezením, pokud existuje.

  • Pokud A je metoda lambda a Tp je vytvořený typ delegáta nebo System.Linq.Expressions.Expression(Of T), kde T je konstruovaný typ delegáta, pro každý typ parametru TL metody lambda a odpovídající typ TDparametru delegáta , nahraďte TaTL a TpTD restartujte proces bez omezení. Potom nahraďte Ta návratovým typem metody lambda a:

    • pokud A je běžná metoda lambda, nahraďte Tp návratovým typem typu delegáta;
    • pokud A je asynchronní lambda metoda a návratový typ delegáta má formulář Task(Of T) pro některé T, nahradit Tp tímto T;
    • pokud A je metoda lambda iterátoru a návratový typ delegáta má formulář IEnumerator(Of T) nebo IEnumerable(Of T) pro některé T, nahraďte Tp ho T.
    • V dalším kroku restartujte proces bez omezení.
  • Pokud A je ukazatel metody a Tp je konstruovaný typ delegáta, použijte typy Tp parametrů k určení, která metoda odkazuje nejvíce na Tp. Pokud existuje metoda, která je nejvhodnější, nahraďte Ta návratovým typem metody a Tp návratovým typem typu delegáta a restartujte proces bez omezení.

  • Tp Jinak musí být konstruovaný typ. Vzhledem k TGobecnému Tptypu ,

    • Pokud Ta je TG, dědí z TG, nebo implementuje typ TG přesně jednou, pak pro každý odpovídající typ argument Tax z Ta a Tpx z Tp, nahradit TaTax a TpTpx restartovat proces omezením obecného argumentu.

    • V opačném případě se pro obecnou metodu nezdaří odvození typu.

Úspěch odvození typu nezaručuje, že metoda je použitelná a sama o sobě.