Avatar billede munkeholm Nybegynder
27. august 2012 - 09:42 Der er 12 kommentarer og
1 løsning

hjælp til nedarvning

hey

jeg har et program hvor jeg skal have lavet en masse funktioner men de alle har en masse til fælles.

så min plan var at bruge Block som parent også ellers lave SleepBlock, TimeBlock osv. som ville arve de forskellige ting fra Block.

det går også fint nok ... men når jeg f.eks. gerne vil lave en List<Block> og vil hente f.eks. en sleepblock ud. er den selvfølgelig en Block og jeg kan derfor ikke tilgå sleep's metoder og parametre ..

Hvor er det jeg misser noget i f.eks.? /

List<Block> list = new List<Block>();
list.add(sleepBlock);

foreach (Block b in list)
{
// HER vil jeg gerne gøre en masse forskelligt ved de her objekter .. altså sleepBlock/TimeBlock osv. som kan være rigtig mange forskellige.

}
Avatar billede runesoft Nybegynder
27. august 2012 - 09:47 #1
Du bliver nødt til at teste på typen og caste til den type du skal bruge.

if(b is SleepBlock){
  ((SleepBlock)b).sleep();
}
Avatar billede munkeholm Nybegynder
27. august 2012 - 09:51 #2
netop det jeg gerne ville undgå da check og typecast på 100 forskellige objekter kunne ende ud i en utrolig lang metode af hvad jeg lige kan forudse. eller er det bare mig ?

if(b is SleepBlock){
// 1
}else if(b is TimeBlock)
{

}else if()

osv. osv.

der er intet galt i at gøre det på den måde ?
Avatar billede bvli Praktikant
27. august 2012 - 10:01 #3
Hej.

Det er nemlig en 'sjov' problemstilling. Du er nødt til at vide noget om co- og contra-variance.

Check evt. denne informative artikel: http://tomasp.net/blog/variance-explained.aspx
Avatar billede mireigi Novice
27. august 2012 - 10:13 #4
En måde at gøre det på er at loope over hver type i din liste.

Det er i princippet det samme som en masse check, men jeg syntes det er mere overskueligt på den måde.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Vehicle> vehicles = new List<Vehicle>();
            vehicles.Add(new Car());
            vehicles.Add(new Car());
            vehicles.Add(new Car());
            vehicles.Add(new MotorCycle());
            vehicles.Add(new MotorCycle());
            vehicles.Add(new MotorCycle());

            Console.WriteLine(vehicles.Sum(f => f.Wheels));
            Console.ReadLine();
            foreach (Car item in vehicles.FindAll(f => f.GetType() == typeof(Car)))
            {
                item.RemoveLeftBackTire();
                item.RemoveRightBackTire();
            }

            foreach (MotorCycle item in vehicles.FindAll(f => f.GetType() == typeof(MotorCycle)))
            {
                item.RemoveBackTire();
            }

            Console.WriteLine(vehicles.Sum(f => f.Wheels));
            Console.ReadLine();
        }
    }

    class Vehicle
    {
        public int Wheels { get; set; }
    }

    class Car : Vehicle
    {
        public Car()
        {
            base.Wheels = 4;
        }

        public void RemoveLeftBackTire()
        {
            base.Wheels--;
        }

        public void RemoveRightBackTire()
        {
            base.Wheels--;
        }
    }

    class MotorCycle : Vehicle
    {
        public MotorCycle()
        {
            base.Wheels = 2;
        }

        public void RemoveBackTire()
        {
            base.Wheels--;
        }
    }
}
Avatar billede munkeholm Nybegynder
27. august 2012 - 10:31 #5
Du har helt ret i det er mere overskueligt, sidder lige og prøver at læse artiklen som blev linket.

Men der ville ikke være nogen indvendinger mod at bruge en liste af checks for at typecaste på den måde ? altså det vil helt sikkert virke og være rimelig simpelt at kode, men rent kode mæssigt er der intet galt i det ?

For så tror jeg at det bliver min løsning efter alt.
Avatar billede mireigi Novice
27. august 2012 - 12:39 #6
Der er ikke noget galt i det nej, men i stedet for en masse if-sætninger, ville jeg nok bruge switch-case i stedet for:

foreach (Vehicle vehicle in vehicles)
{
  switch (vehicle.GetType())
  {
      case typeof(Car):
        ((Car)vehicle).RemoveLeftBackTire();
        break;
      case typeof(MotorCycle):
        ((MotorCycle)vehicle).RemoveBackTire();
        break;
      default:
        break;
  }
}
Avatar billede mireigi Novice
27. august 2012 - 12:54 #7
Kiggede lidt rundt, og fandt ud af, at du kan nøjes med én metode, hvis du bruger Reflection:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Vehicle> vehicles = new List<Vehicle>();
            vehicles.Add(new Car());
            vehicles.Add(new Car());
            vehicles.Add(new Car());
            vehicles.Add(new MotorCycle());
            vehicles.Add(new MotorCycle());
            vehicles.Add(new MotorCycle());

            Console.WriteLine(vehicles.Sum(f => f.Wheels));
            Console.ReadLine();

            foreach (Vehicle vehicle in vehicles)
            {
                vehicle.InvokeMethod(typeof(Car), vehicle, "RemoveLeftBackTire", null);
                vehicle.InvokeMethod(typeof(MotorCycle), vehicle, "RemoveBackTire", null);
            }


            Console.WriteLine(vehicles.Sum(f => f.Wheels));
            Console.ReadLine();
        }
    }

    class Vehicle
    {
        public int Wheels { get; set; }

        public void InvokeMethod(Type type, object classInstance, string methodName, object[] parameters)
        {
            if (type != null && classInstance.GetType() == type)
            {
                MethodInfo method = type.GetMethod(methodName);
                if (method != null)
                {
                    object result = null;
                    int parameterCount = method.GetParameters().Length;
                    if (parameterCount == 0)
                    {
                        result = method.Invoke(classInstance, null);
                    }
                    else
                    {
                        result = method.Invoke(classInstance, parameters);
                    }
                }
            }
        }

    }

    class Car : Vehicle
    {
        public Car()
        {
            base.Wheels = 4;
        }

        public void RemoveLeftBackTire()
        {
            base.Wheels--;
        }

        public void RemoveRightBackTire()
        {
            base.Wheels--;
        }
    }

    class MotorCycle : Vehicle
    {
        public MotorCycle()
        {
            base.Wheels = 2;
        }

        public void RemoveBackTire()
        {
            base.Wheels--;
        }
    }
}
Avatar billede runesoft Nybegynder
27. august 2012 - 13:11 #8
Nu ved jeg jo ikke helt hvad der er du vil. Du kunne gøre det at du laver en abstrakt metode på Block, og implementerer den på dine subklasser. Så ville du ikke skulle caste dine objekter før du kalder dem.
Avatar billede mireigi Novice
27. august 2012 - 13:21 #9
@runesoft (#8): Det er vel kun holdbart så længe det giver mening at metoden hedder/gør det samme? Vil nødig være den der skal vedligeholde et system, hvor hver klasse har X antal metoder med samme navn, men hver metode gør noget forskelligt.
Avatar billede arne_v Ekspert
28. august 2012 - 00:54 #10
Jeg er enig med #8.

Hvis ikke det giver mening at have en abstrakt metode alle overrider, saa giver det heller ikke mening at have en List<basistype> og ville goere noget paa alle elementer.

Hvis man mangler et godt metode navn, saa er Execute brugt en del til den slags.
Avatar billede munkeholm Nybegynder
28. august 2012 - 09:58 #11
grunden til jeg har valgt at have en basictype er fordi så kan parameter hentes uden at kende den specifike type

f.eks. indeholder alle elementer noget perlcode som dog er forskelligt og her slipper jeg så for tjekket efter typen af element.


hele problemet ligger som sagt i at jeg har en liste af block objekter som jeg vil tilføje til et listview/listbox og her har jeg brug for specifike parameter som kun nogle af mine elementer har.


men i har helt ret, der er nogle metoder som kunne være smarte at lave abtrakte i block og udfylde.
Avatar billede janus_007 Nybegynder
28. august 2012 - 22:45 #12
munkeholm, du skal bare lave en type scanner eller bruge et fornuftigt Dependency Injection framework, så kan du hente typen ud på navnet og behøver ikke det prut med switch/ case eller andet for-each-guf :)
Avatar billede mireigi Novice
29. august 2012 - 01:52 #13
Vil lige henlede opmærksomheden til mit indlæg i #7. Det kan gøre, hvad du har behov for, uden at du behøver ændre på eksisterende nedarvede klasser. Det er kun på basis-klassen at metoden skal ligge.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester