Avatar billede lasserasch Juniormester
17. januar 2007 - 15:58 Der er 30 kommentarer og
1 løsning

Array index out of bounds fejl.

Hejsa.

Jeg har følgende stykke kode, som jeg bruger til at slette aftaler fra mit C# program i min outlook kalender.

for (int J = 1; J <= I; J++)
            {
                try
                {
                    oAppt = (Outlook.AppointmentItem)oItems.Item(J);

                   
                    if (oAppt.Body.StartsWith("Dette er en automatisk genereret"))
                        {
                            System.Console.WriteLine("Sletter aftalen for med overskriften : " + oAppt.Subject + " - Dato : " + oAppt.Start);
                          String T = Convert.ToString(oAppt.Subject);
                            oAppt.Delete();
                        }
 
                }
                catch (Exception Ex)
                {
                    System.Console.WriteLine(Ex.Message);
              }

            }



Den kører et antal aftaler igennem, men så pludselig fejler den med beskeden : "Array index out of bounds."

Hvis jeg f.eks. har 332 objekter som opfylder kravene i mit outlook, så stopper den når den har slettet 152 af aftalerne. Nr. 153 siger den denne fejl på!

Hvis jeg så fortsætter, så kører den lidt igen og stopper så igen!

Det kan jeg så blive ved med indtil den har slettet dem alle... Og hvis jeg bare gider trykker "Continue" mange gange nok, så får den slettet dem alle!


Hvad kan være galt?

/Lasse
Avatar billede kalp Novice
17. januar 2007 - 16:13 #1
tror vi skal se noget andet kode.. du har jo også en variabel i..
men prøv dette

foreach(Outlook.AppointmentItem oAppt in oItems)
            {
                try
                {

                   
                    if (oAppt.Body.StartsWith("Dette er en automatisk genereret"))
                        {
                            System.Console.WriteLine("Sletter aftalen for med overskriften : " + oAppt.Subject + " - Dato : " + oAppt.Start);
                          String T = Convert.ToString(oAppt.Subject);
                            oAppt.Delete();
                        }
 
                }
                catch (Exception Ex)
                {
                    System.Console.WriteLine(Ex.Message);
              }

            }
Avatar billede bitmatic Nybegynder
17. januar 2007 - 16:19 #2
Jeg tror det er fordi du itererer igennem en liste samtidig med at du fjerner elementer fra listen.

Du initialiserer jo formodentlig variablen "I" til antallet af aftaler. Det antal vil imidlertid blive mindre og mindre efterhånden som du fjerner elementer, med det resultat at du til sidst forsøger at læse ud over enden af listen.

Jeg er i øvrigt også rimeligt sikker på, at den fremgangsmåde du har valgt vil betyde, at du springer elementer over, som altså slet ikke bliver checket.

måske kunne du prøve at sige:
for (int J = 1; J <= oItems.Count; J++)
i stedet for:
for (int J = 1; J <= I; J++)
Så tror jeg din exception forsvinder, men det løser ikke problemet med at du springer elementer over.
Avatar billede bitmatic Nybegynder
17. januar 2007 - 16:21 #3
ok... kalp var hurtigere :-)

I øvrigt kan jeg heller ikke se ideen i "String T = Convert.ToString(oAppt.Subject);" du bruger jo ikke T til noget.
Avatar billede lasserasch Juniormester
17. januar 2007 - 16:26 #4
Hejsa.

bitmatic, jeg kan godt se din logik. Jeg prøver lige det du siger.

Hvad angår at jeg springer objekter over, så tror jeg nok at jeg har fat i dem alle... For hvis jeg samtidig åbner mit outlook, søger efter kalender aftaler med teksten "Dette er en automatisk genereret"... Så kan jeg følge resultatet løbende, hvor jeg kan se at den til sidst kommer ned på 0.


/Lasse
Avatar billede lasserasch Juniormester
17. januar 2007 - 16:28 #5
Nej, den der med string T = osv.... Det var bare fordi jeg lige havde et break point, og så gerne lige ville se hvad overskriften var på hver kalenderaftale. Glemte jeg lige at få slettet igen inden jeg copy pasted mine kode over! Sorry....
Avatar billede lasserasch Juniormester
17. januar 2007 - 16:30 #6
Foreach kan jeg ikke bruge sådan umibbelbart, den giver følgende fejl :

foreach statement cannot operate on variables of type 'Outlook.Items' because 'Outlook.Items' does not contain a public definition for 'GetEnumerator'
Avatar billede kalp Novice
17. januar 2007 - 16:33 #7
Du skal angive den type objekter du har i oItems.. Klassenavnet på dem altså..

foreach(KlasseNavn oAppt in oItems)


så burde det virke. jeg gættede bare på navnet..
Avatar billede kalp Novice
17. januar 2007 - 16:36 #8
eksempel.

string[] liste = new string[3];
list[0] = "Hejsa";
list[1] = "Det her er";
list[2] = "Godt";

foreach(string tekst in liste)
{
Console.WriteLine(tekst);
}

dvs.
den første string i løkken her angiver hvilken type objekter jeg vil løbe igennem.
tekst er bare den variabel de skal gemmes i.
liste er den struktur jeg vil løbe igennem.
foreach(string tekst in liste)

bitmatic's løsning gør det samme så den burde virke.
Avatar billede bitmatic Nybegynder
17. januar 2007 - 16:52 #9
Objekter skal kunne returnere en enumerator for at virke med foreach. Det er der noget der tyder på at Outlook.AppointmentItem ikke kan. Derfor vikrer det ikke med foreach.
Avatar billede lasserasch Juniormester
17. januar 2007 - 17:38 #10
Hmmm.... Kunne ikke lige se mig ud af det du skrev kalp med det eksempel.

Men det er nu også lige meget! Jeg fik det til at virke ved at bruge oitems.count i stedet for I, som du skrev bitmatic.

Altså :  for (int J = 1; J <= oItems.Count; J++)

Det er jo mega logisk når man lige tænker sig om...
Og den får slettet alle entries. Jeg kan i hvert fald ikke finde nogle tilbage i mit outlook bagefter.

Så hvis i begge smider et svar, så får i points :-)

Jeg takker for hjælpen!

/Lasse
Avatar billede kalp Novice
17. januar 2007 - 17:50 #11
men hoppede stadig ned i catch delen på din exception?
Avatar billede lasserasch Juniormester
17. januar 2007 - 18:19 #12
Tænker du på dit eksempel?

Jeg har ikke forsøgt at bruge det. ville lige prøve det bitmatic skrev først. Og det fungerede for mig, så var der jo ingen grund til at prøve noget andet...

/Lasse
Avatar billede kalp Novice
17. januar 2007 - 18:24 #13
anyways:)
lad min portion af points gå til bitmatic.
han virker som en fornuftig ny bruger på E.
Avatar billede lasserasch Juniormester
17. januar 2007 - 19:52 #14
Nå, jeg fandt jo ud af at bitmatic havde ret i at den ikke sletter alle elementer alligevel!

kalp, kan du ikke give et eksempel på hvordan du ville opstille en regl for hvilke elementer der skal løbes igennem, for at fjerne den fejl jeg skrev tidligere...

Jeg forstår nogenlunde hvad du mener i dit eksempel, men formår åbenbart ikke at få det omsat til noget brugbart i mit projekt.

Min kode ser pt. således ud :

private void Do_resetoutlook_entries(Outlook.NameSpace NS)
{

Outlook.NameSpace oNS = NS;
Outlook.MAPIFolder oFolder = (Outlook.MAPIFolder)oNS.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderCalendar);
Outlook.Items oItems = (Outlook.Items)oFolder.Items;

foreach (Outlook.AppointmentItem oAppt in oItems)
{
try
{
if (oAppt.Body != null)
{
if (oAppt.Body.StartsWith("Dette er en automatisk genereret"))
{
System.Console.WriteLine(Convert.ToString(J) + " ud af " + Convert.ToString(oItems.Count) + " - Sletter aftalen for med overskriften : " + oAppt.Subject + " - Dato : " + oAppt.Start);

oAppt.Delete();

}
}
}


catch (Exception Ex)
{
System.Console.WriteLine(Ex.Message);
}

}
}
Avatar billede kalp Novice
17. januar 2007 - 19:57 #15
før vi kigger på mit så tror jeg måske en forståelse af hvad det er der sker måske kan afklare problemet..
der er ting i din løkke som jeg undre mig over..

for (int J = 1; J <= oItems.Count; J++)

normal ville den vel se sådan ud

for (int J = 0; J < oItems.Count; J++)
Avatar billede lasserasch Juniormester
17. januar 2007 - 20:09 #16
Jo, den linie er jo så blevet erstattet af :

--------
foreach (Outlook.AppointmentItem oAppt in oItems)
--------

Grunden til at jeg skrev 1 og ikke 0, er at jeg bruger J i mit script når jeg skal referere til hvilket outlook kalender aftale det er jeg vil hente.

Det skete i linien : 
----------
oAppt = (Outlook.AppointmentItem)oItems.Item(J);
----------

Og der findes ikke noget 0. Den første kalenderaftale ligger på 1.

Så derfor denne fremgangsmetode.
Og i mit tilrettede script som postet herover, har jeg glemt en ting mere...

Denne linie :

---------
System.Console.WriteLine(Convert.ToString(J) + " ud af " + Convert.ToString(oItems.Count) + " - Sletter aftalen for med overskriften : " + oAppt.Subject + " - Dato : " + oAppt.Start);
---------

Skal i stedet være :

---------
System.Console.WriteLine("Sletter aftalen for med overskriften : " + oAppt.Subject + " - Dato : " + oAppt.Start);
---------
Avatar billede kalp Novice
17. januar 2007 - 20:14 #17
ja men synes du sagde min foreach ikke fungerede så ville hellere rette i det der "næsten" fungerede:)


men i hvertfald.. her

if (oAppt.Body != null)

skal du nok også lige tjekke sådan her

if (oAppt.Body != null || oAppt.Body != "")

og endnu bedre.. hvis Body er en string.. så

if (oAppt.Body != null || oAppt.Body.Trim() != "")
Avatar billede lasserasch Juniormester
17. januar 2007 - 20:19 #18
ok, hermed rettet. Og ja, det er en string...

Ja, din foreach fungerede ikke, den fejlede med fejlen :

foreach statement cannot operate on variables of type 'Outlook.Items' because 'Outlook.Items' does not contain a public definition for 'GetEnumerator'


Men sagde du ikke at man kunne gøre noget for at rette det?

/Lasse
Avatar billede lasserasch Juniormester
17. januar 2007 - 20:19 #19
Den fejler stadig med den fejl jo.
Avatar billede kalp Novice
17. januar 2007 - 20:29 #20
ja måske men det det er svært at sige fordi jeg ikke kender til resten af systemet... jeg ville nok prøve at lave en foreach på
Outlook
og ikke
Outlook.AppointmentItem

men det ville kræve nogle ændringer selvfølgelig i koden flere steder..

man kan sagtens få det andet til at virke, men det kræver at du er lidt detaljeret:) så man har en chance.. problemet er nemlig ikke stort, men det er bare et manglende overblik fra min side af der gør at jeg ikke kan komme med løsningen.

den slettede ikke nogle elementer sagde du ? var der noget specielt ved disse f.eks?

og jeg kunne stadig godt tænke mig at se hvor variablen "i" som var med i dit første kom fra.. evt. hvordan du udfyler oItems med værdier..

så tror jeg vi er der:)
Avatar billede lasserasch Juniormester
17. januar 2007 - 21:00 #21
Jeg går lige lidt tilbage i ændringerne på min kode. Koden er ikke så stor og indeholder ingen følsomme data. Jeg uploader den lige på min hjemmeside, så kan du jo se hele koden hvis det var.

OK?

Du vil nok ikke kunne køre koden, da den laver et SQL kald og hente nogle medarbejder data ud fra vores gamle AS/400 system. Jeg laver et udtræk hver nat fra AS/400 til en SQL server, og henter så medarbejder data fra denne SQL Server. Her har jeg bare ændret password i min kode pt, så der er ingen følsomme ting i den overhovedet.

Du falder sikkert over nogle andre ting, jeg kunne gøre noget mere smart. For mig gælder det dog pt. bare om at få dette til at virke. Så kan jeg fintrimme koden bagefter!

Den kigger på de outlook profiler der er oprettet på ens PC, og bruger dem til at oprette forbindelse til folks outlook kalendere.

Systemet skal bruges til at oprette medarbejderes fødselsdatoer og jubilæer i forskellige outlook kalendere.

Når en medarbdejder ansættes oprettes han i AS/400 systemet, som er vores løn styringssystem bl.a.

Et døgn efter er medarbejderen så med i SQL udtrækket jeg laver hver nat, og hans fødselsdag osv oprettes så automatisk i outlook...

Sourcekoden har jeg lagt på http://storetasker.dk/outlooksrc.zip

/Lasse
Avatar billede lasserasch Juniormester
17. januar 2007 - 21:03 #22
Det som altså er galt med den kode der ligger der pt, er at den ikke sletter alle aftaler.

Den fejler ikke og sletter en del kalenderaftaler. Når den er nået en del af vejen, så stopper den dog med at slette og begynder i stedet at oprette aftaler igen, ud fra resultaterne i det SQL udtræk den laver. Oprettelserne fungerer perfekt!

Så eneste fejl i den kode, der ligger der pt, er at den ikke sletter specielt mange aftaler før den begynder at oprette. Det betyder så at mange aftaler kommer til at ligge 2 gange, og næste gang 3 gange osv osv osv...

/Lasse
Avatar billede lasserasch Juniormester
17. januar 2007 - 21:08 #23
Det skal nok lige siges, at kommentarerne i koden ikke er tiltænkt dig kalp. Mere hvis en anden skal rette noget når jeg engang om 100 år er død og borte eller forlader virksomheden, som jeg skal lave dette for...

/Lasse
Avatar billede kalp Novice
17. januar 2007 - 22:22 #24
jeg bliver nød til at se på det i morgen med mit VS2005, men men men.. måske virker det allerede sådan her hvis du er heldig.. ellers må jeg løse det i morgen.. men den her må være tæt på!

Outlook.AppointmentItem oAppt = null;

foreach (object data in oItems)
{
                try
                {
    oAppt = data as Outlook.AppointmentItem;
if(oAppt != null) {
                   
                    if (oAppt.Body.StartsWith("Dette er en automatisk genereret"))
                        {
                            System.Console.WriteLine("Sletter aftalen for med overskriften : " + oAppt.Subject + " - Dato : " + oAppt.Start);
                          String T = Convert.ToString(oAppt.Subject);
                            oAppt.Delete();
                        }
 
                }
}
                catch (Exception Ex)
                {
                    System.Console.WriteLine(Ex.Message);
              }

            }
Avatar billede kalp Novice
17. januar 2007 - 22:23 #25
hold kæft det står sjusket:S
men hvis paranteserne er rigtige så tror jeg altså det virker.
Avatar billede kalp Novice
17. januar 2007 - 22:35 #26
ps.
denne linje
oAppt = data as Outlook.AppointmentItem;

vil returnere null hvis data objektet ikke er et .AppointmentItem objekt..

så koden skal virke og hvis ikke er de elementer der ikke er slettet en anden type objekter..
Avatar billede bitmatic Nybegynder
18. januar 2007 - 00:48 #27
Hvis du har problemer med at den ikke fjerner dem alle, tror jeg at det hænger sammen med det jeg skrev tidligere om at du springer elementer over, fordi du fjerner elementer imens du itererer igennem listen. Det kommer lidt an på hvorledes iteratoren er implementeret helt nede i maven på containeren, men det kunne være det der er problemet.

Et oversimplificeret eksempel (pseudokode):

Lad os lege at jeg står med et array af karakterer der ser sådan her ud:
X = {A,B,C,D,E}

Jeg vil gerne fjerne alle konsonanterne, så jeg laver noget lignende af:
for(int i=0; i<X.Count; ++i)
{
  if (X[i].IsConsonant)
    X[i].RemoveFromArray();
}

Første gang løkken kører kigger koden på X[0] som er et A. Koden gør ingenting.
Anden gang løkken kører kigger koden på X[1] som er et B. Koden fjerner altså B'et.
Tredje gang løkken kører kigger koden på X[2] som er et D !!! (fordi B'et jo er fjernet, så arrayet ser nu sådan her ud {A,C,D,E}. Koden har altså sprunget C'et over.

Det er da en teori :-)

Men om den er rigtig afhænger helt af hvordan din container er skruet sammen.
Avatar billede lasserasch Juniormester
18. januar 2007 - 07:08 #28
Hej til jer begge.

Til kalp : Den kommer stadig med samme fejl omkring GetEnumerator
efter jeg har rettet til det kode eksempel du skriver sidst.

Til Bitmatic. Du har ret, mit problem er som du beskriver. Men hvordan kan man løse det? Hvordan får man den til at løbe ALLE elemente igennem når listen bliver kortere og kortere?

Jeg kunne jo løbe listen igennem 500 gange. Det ville nok virke for mig pt. men det er jo ingen holdbar løsning.
Avatar billede kalp Novice
18. januar 2007 - 08:13 #29
meget mystisk... anyways.. jeg søgte lidt og fandt dette
http://msdn2.microsoft.com/en-us/library/ms268996(VS.80).aspx

så man kan godt bruge foreach.. kan ikke se hvorfor det ikke virker
Avatar billede lasserasch Juniormester
18. januar 2007 - 08:30 #30
Søgte også lidt selv her sent i aftes...

Fandt ud af at har man Office 2003 så er der en GetEnumerator man kan bruge. Men jeg har kun Office XP installeret, og den har ikke nogen!

Jeg har nu installeret Office 2003, men den har så andre "skavanker"... Så jeg tænkte på en anden løsning.

Kunne man ikke bare lave et nyt array i sin kode. Og når jeg løber alle kalenderaftaler igennem, så i stedet for at slette dem der opfylder kravet om bestemt indhold, så bare tilføje dem til det nye array. Hver kalenderaftale har et ID, så jeg kunne jo bare tilføje dette ID til det nye array.

Og når man så er færdig med at løbe dem alle igennem, så tage alle objekter i det nye array og for hvert af disse slette den kalenderaftale der har det pågældende ID.

Lyder det rodet eller rimelig fornuftigt?

/Lasse
Avatar billede bitmatic Nybegynder
18. januar 2007 - 10:27 #31
Hvis ikke oItems er read-only kan du måske bare løbe den igennem, kopiere de aftaler du vil beholde over i et nyt array, og til sidst sætte oItems lig med det nye array.

En alternativ løsning er at dekrementere tælleren hver gang du har fjernet et element, for at kompensere for at arrayet er ændret....

for (int J = 1; J <= oItems.Count; J++)
{
  try
  {
    oAppt = (Outlook.AppointmentItem)oItems.Item(J);

    if (oAppt.Body.StartsWith("Dette er en automatisk genereret"))
    {
      System.Console.WriteLine("Sletter aftalen for med overskriften : " + oAppt.Subject + " - Dato : " + oAppt.Start);

      oAppt.Delete();
      J--;
    }
  }
  catch (Exception Ex)
  {
    System.Console.WriteLine(Ex.Message);
  }
}

Men så er du nok lige nødt til at teste at det virker omkring det første og sidste element i array'et. Det tror jeg nu nok det gør. Men så er du ved at være ude i en løsning hvor du itererer igennem et array, imens du ændrer både array'et og iteratoren.... Det er ikke nødvendigvis særligt læsbart når du kommer tilbage til koden om 1 år :-)
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