[ Boris B. @ 16.11.2010. 09:35 ] @
Code (csharp):

public void Overload(params object[] p)
{
   ...
}

public void Overload(KonkretnaKlasa k)
{
   ...
}
 


Kako ovo uopšte funkcioniše, nije valjda da u runtime testira tipove pre svakog poziva metoda?
[ mmix @ 16.11.2010. 09:51 ] @
Zanimljivo,

moguce je da params dolazi komapjleru na red tek ako istrosi sve ostale. Tj ako je dklarisani parametar KonkretnaKlasa ili nasledjeno onda zove drugi u suprotnom sove params. To isto znaci i da boxovana KonkretnaKlasa mora da ode u params metod (inace je runtime provera).
[ Boris B. @ 16.11.2010. 14:54 ] @
Ako stvarno testira u runtime-u tipove, onda zbog podrske za ovaj specifican slucaj gube dosta na performansama pri pozivanju metoda, jer ako nista drugo mora postojati bar jedan IF (ImaOverloadSaParams) THEN TestirajTipove, sto bi znacilo par dodatnih instrukcija pre pozivanja *svakog* metoda, cak i onih koji nemaju overload sa params. Sad zamisli to u nekom N^N scenariju pa vidi koliko se gubi na performansama.

Znam da su se za razliku od Jave odlucili za keyworde virtual/override zbog izbegavanja VMT-a i ubrzavanja pozivanja ne-virtualnih metoda, ako posmatras iz te perspektive onda ovo izgleda kao propust. Mada je sasvim moguce da prilikom kompajliranja staticki analajzer oznaci ovakve param-overloadovane metode kao specijalne i onda inlajnuje provere samo za njih, mada istu stvar su mogli da urade i kod virtualnih metoda i da svi metodi postanu virtualni bez potrebe za specificnim keywordima.
[ mmix @ 16.11.2010. 15:42 ] @
Iskreno sumnjam, u trenutku kompajliranja poziva ti vec imas stvarne parametre i njihove deklarisane tipove, poenta je samo koji overload ce da uzme i kojim poretkom ako je ambiguous. Moja pretpostavka je da ide od specificnog ka generickom. Nemam sad VS pri sebi, probaj da boxujes instancu u object i onda pozovi overload. Ako pozove params verziju onda je staticki poziv odredjen pri kompajliranju. Ako pozove KonkretnaKlasa overload onda je runtime check i dinamicki poziv (mada, kazem, sumnjam)

U principu prica bi trebalo da se svede na overload bez params ako jedan prima object a drugi KonkretnaKlasa. Ono sto ne bi smelo da postoji po ovom statickom poravnavanju je overload sa "params KonkretnaKlasa[]" jer onda se definitivno ne zna koji se poziva.
[ Shadowed @ 16.11.2010. 15:58 ] @
Code (csharp):

class Program
    {
        static void Main(string[] args)
        {
            TestClass tc = new TestClass();
            object o = tc;
            Console.WriteLine(x(tc));
            Console.WriteLine(x(o));
            Console.ReadLine();
        }

        static String x(TestClass tc) { return "x"; }

        static String x(params object[] p) { return "y"; }

        static String x(object o) { return "z"; }

        static String x(params TestClass[] tc) { return "u"; }
    }

    class TestClass
    { }
 


Rezultat:
x
z

:)

Ako se izbaci "z" funkcija, rezultat je x, y.
[ mmix @ 16.11.2010. 16:02 ] @
A ako izbacis x?
[ Shadowed @ 16.11.2010. 16:11 ] @
Onda je u, z. Rekao bih da ide po principu prvo ono sto se tacno poklapa (1 parametar trazi, 1 dat, tipovi se poklapaju) pa onda isto to a ne poklapaju se (ako izbacim i "x" i "u", dobija se z, z) pa tek onda params sa poklapanjem tipova pa bez poklapanja.
[ mmix @ 16.11.2010. 20:06 ] @
Definitivno komapjlersko povezivanje, nema runtime provere.
[ Boris B. @ 17.11.2010. 09:43 ] @
Zanimljivo, znaci ipak je static resoultion. Dodaj jos na ovo i default parametre i inheritance, i cela stvar postaje jedan lep mali overload hell... :)

Napravio sam test primer:
Code (csharp):

    class Base
    {
        protected virtual void Overload(string s)
        {
            Console.WriteLine("Base typed vanilla called: " + s);
        }

        protected virtual void Overload(string s1, string s2 = "Default")
        {
            Console.WriteLine("Base typed default param called: {0}, {1}", s1, s2);
        }

        protected virtual void Overload(params string[] s)
        {
            Console.WriteLine("Base typed params called: " + String.Join(", ", s));
        }

        protected virtual void Overload(object s)
        {
            Console.WriteLine("Base untyped vanilla called: " + s);
        }

        protected virtual void Overload(object s1, object s2 = null)
        {
            s2 = s2 ?? "Default";
            Console.WriteLine("Base untyped default param called: {0}, {1}", s1, s2);
        }

        protected virtual void Overload(params object[] s)
        {
            Console.WriteLine("Base untyped params called: " + String.Join(", ", s));
        }        
    }

    class Program : Base
    {
        void Overload(object o, string s = "Default")
        {
            Console.WriteLine("Derived mixed called: {0}, {1}", o, s);
        }

        void Go()
        {
            var s = "String";
            var o = (object)"Object";

            Overload(s);
            Overload(s, s);
            Overload(s, s, s);
            Console.WriteLine();

            Overload(o);
            Overload(o, o);
            Overload(o, o, o);
            Console.WriteLine();

            Overload(s, o);
            Overload(o, s);            
            Console.WriteLine();

            Console.ReadKey();            
        }

        static void Main(string[] args)
        {
            new Program().Go();
        }
    }
 


Rezultat
Code:

Derived mixed called: String, Default
Derived mixed called: String, String
Base typed params called: String, String, String

Derived mixed called: Object, Default
Base untyped default param called: Object, Object
Base untyped params called: Object, Object, Object

Base untyped default param called: String, Object
Derived mixed called: Object, String