Mechanizm refleksji a przeciążone funkcje

0

Witam. Staram się ogarnąć pakiety .NET, mechanizm refleksji, późne wiązanie itp. Stworzyłem sobie pakiet autoIosoba.dll, w pakiecie zawarte są 2 klasy, Auto oraz Osoba. Klasa Auto składa się z tego z czego zazwyczaj składają się klasy, 2 konstruktory, 2 zdarzenia, kilka pól prywatnych i publicznych metod. Dla mojego problemu istotne jest to że w klasie są zdefiniowane 2 wersje metody zwieksz, która ma zwiększyć wartość pola szybkość. Jedna wersja metody jest bez parametru, druga przyjmuje parametr typu int o wartość którego zostanie zwiększona wartość pola szybkość. W nowym projekcie robię coś takiego:

 
            Assembly autoIosoba = Assembly.Load("autoIosoba");
            Type auto = autoIosoba.GetType("autoIosoba.Auto");
            ConstructorInfo ci = auto.GetConstructor(Type.EmptyTypes);
            Object auto1 = ci.Invoke(new object[] { });
            MethodInfo zwieksz = auto.GetMethod("zwieksz");  //błąd, znaleziono niejednoznaczne dopasowanie
            object[] parameters = null;                   //chcę przykładowo wywołać metodę zwieksz bez parametrów
            zwieksz.Invoke(auto1, parameters);

Zdaję sobie sprawę że błąd powodowany jest przez to że metoda zwieksz jest przeciążona i kompilator nie wie o którą mi chodzi, mimo to nie wiem jak ten problem rozwiązać. Kiedy próbuje wywołać inną metodę, np. wyswietl, wszystko jest w porządku. Co na to poradzić?

0

GetMethod po polsku oznacza WeźMetodę. JEDNĄ. Ty masz dwie metody o tej samej nazwie, więc metoda znajdująca jedną, nie ma logicznego prawa zadziałać.
Użyj np. metody GetMethods, która zwróci Ci tablicę MethodInfo i w niej szukaj swojej metody.

0

No tak, przeoczyłem to. Dzięki :)

0

object[] parameters = null; //chcę przykładowo wywołać metodę zwieksz bez parametrów
zwieksz.Invoke(auto1, parameters);

a dlaczego nie

zwieksz.Invoke(auto1, null);                   //chcę przykładowo wywołać metodę zwieksz bez parametrów
0

No tak, oczywiście może być null, na początku tak miałem ale błąd sprawił że w różnych miejscach szukałem rozwiązania i zmieniłem null na pustą tablicę obiektów. Ok, zrobiłem to tak:

            Assembly autoIosoba = Assembly.Load("autoIosoba");
            Type auto = autoIosoba.GetType("autoIosoba.Auto");
            ConstructorInfo ci = auto.GetConstructor(Type.EmptyTypes);
            Object auto1 = ci.Invoke(new object[] { });
            MethodInfo[] zwieksz = auto.GetMethods();
            MethodInfo zwieksz1 = null;   //do tego pola przypiszę 1 metodę o nazwie zwiększ
            MethodInfo zwieksz2 = null;   //a do tego drugą
            
            foreach (var item in zwieksz)   //przeszukanie tablicy zawierającej wszystkie tablice
            {
                if (item.Name == "zwieksz")
                {
                    if (zwieksz1 == null)  //przypisanie 1 odpowiedniego wyniku do 1 zmiennej
                    {
                        zwieksz1 = item;
                    }
                    else if (zwieksz2 == null)  //przypisanie 2 wyniku do 2 zmiennej
                    {
                        zwieksz2 = item;
                    }
                }
            }
            MethodInfo mojaMetoda = null; //zmienna do której przypiszę właściwą, bezparametrową metodę zwieksz
            ParameterInfo[] parametry1 = zwieksz1.GetParameters();
            ParameterInfo[] parametry2 = zwieksz2.GetParameters();
            if (parametry1.Length == 0)   //sprawdzam czy metoda jest bezparametrowa, takiej wlasnie szukam
            {
                mojaMetoda = zwieksz1;
            }
            else if (parametry2.Length == 0)    //sprawdzam czy metoda jest bezparametrowa, takiej wlasnie szukam
            {
                mojaMetoda = zwieksz2;
            }
            mojaMetoda.Invoke(auto1, null);
            Console.Read(); 

Wszystko ładnie działa. teraz zastanawiam się czy można zrobić to jakoś inaczej, to znaczy ładniej i czytelniej? Może można przeszukać tablicę MethodInfo[] zwieksz zapytaniem LINQ które od razu zwróci metodę zwieksz bez parametrów? A może cel można osiągnąć w jeszcze prostszy sposób?

0

Ten kod to jakaś tragedia, gorzej się tego nie dało napisać. Po co tyle zmiennych pomocniczych, pętli i ifów?

Assembly autoIosoba = Assembly.Load("autoIosoba");
Type auto = autoIosoba.GetType("autoIosoba.Auto");
ConstructorInfo ci = auto.GetConstructor(Type.EmptyTypes);
Object auto1 = ci.Invoke(new object[] { });

// metodą małych kroczków:
// wybieramy wszystkie metody o nazwie "zwieksz"
List<MethodInfo> metodyZwieksz = new List<MethodInfo>();
foreach (MethodInfo mi in auto.GetMethods())
{
    if (mi.Name == "zwieksz")
    {
        metodyZwieksz.Add(mi);
    }
}

// znajdujemy tą bez parametru
MethodInfo metodaBezParametru;
foreach (MethodInfo mi in metodyZwieksz)
{
    if (mi.GetParameters().Length == 0)
    {
        metodaBezParametru = mi;
        break;
    }
}

// lepiej od razu w jednej pętli:
MethodInfo metodaBezParametru2;
foreach (MethodInfo mi in auto.GetMethods())
{
    if (mi.Name == "zwieksz" && mi.GetParameters().Length == 0)
    {
        metodaBezParametru2 = mi;
        break;
    }
}

// albo w LINQ:
var metodaBezParametru3 = auto.GetMethods().SingleOrDefault(q => q.Name == "zwieksz" && q.GetParameters().Length == 0); 
0

Dzięki somekind, teraz to ma ręce i nogi.

1 użytkowników online, w tym zalogowanych: 0, gości: 1