Gå til innhold

C#: Feilmelding: "ObjectDisposedException was unhandled - Cannot write to a closed TextWriter"


Anbefalte innlegg

Hei! Har laget et lite program, men støter på noen leifer.. :whistle:

 

Her er koden:

 

KODE FØR AKTUELL FUNKSJON

 

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace PrimeI
{
   public partial class Form1 : Form
   {
       public Form1()
       {
           InitializeComponent();
           label6.Text = "";
       }
       private void DoIt_Click(object sender, EventArgs e)
       {
           if (bulks.Checked == true)
           {
                   label1.Text = "";
                   label2.Text = "";
                   string start = startingAt.Text;
                   string number = NumberOf.Text;
                   startingAt.Text = "Calculating...";
                   NumberOf.Text = "This might take a while...";
                   string[] enter = { start, number, bulksSize.Text, bulksNumber.Text };
                   string location = CalcBulks(enter);

                   startingAt.Text = "Finished calculating.";
                   NumberOf.Text = "The primes are located in:";
                   label6.Text = location;
           }
           else
           {
               if (checkBox1.Checked != true)
               {
                   label1.Text = "";
                   label2.Text = "";
                   string start = startingAt.Text;
                   string number = NumberOf.Text;
                   startingAt.Text = "Calculating...";
                   NumberOf.Text = "This might take a while...";
                   string[] enter = { start, number };
                   string location = Calc(enter);

                   startingAt.Text = "Finished calculating.";
                   NumberOf.Text = "The primes are located in:";
                   label6.Text = location;
               }
               else
               {
                   label1.Text = "";
                   label2.Text = "";
                   string start = startingAt.Text;
                   string number = NumberOf.Text;
                   startingAt.Text = "Calculating...";
                   NumberOf.Text = "This might take a while...";
                   string[] enter = { start, number };
                   string location = CalcOne(enter);

                   startingAt.Text = "Finished calculating.";
                   NumberOf.Text = "The primes are located in:";
                   label6.Text = location;
               }
           }
           this.Close();
       }
       private string Calc(string[] startNumber)
       {
           uint primeCount = 0;
           string path = @"C:\primeresult.txt";
           System.IO.StreamWriter mySW = new System.IO.StreamWriter(path, false);
           double primeEnter = Convert.ToDouble(startNumber[0]) - 1;
           int numberOfPrimes = Convert.ToInt32(startNumber[1]); //numberOfPrimes = antall programmet skal finne.
           if (primeEnter + 1 <= 3)
           {
               [size="5"][b]mySW.WriteLine("2");[/b][/size]
               mySW.WriteLine("3");
               primeEnter = 4;
               primeCount += 2;
           }
           bool tester = false; //Hvis tester = true så er det et primtall.
           for (ushort i = 0; primeEnter < numberOfPrimes; i++) //egentlig hele programmet her. Det repeteres til du finner "numberOfPrimes" primtall.
           {

               while (tester == false) //mens det ikke er et primtall
               {
                   primeEnter++; //legg til én og prøv igjen. Dette er grunnen for at jeg la til (-1) i linje 17.
                   tester = IsPrime(primeEnter); //denne returnerer true hvis den finner at det er et primtall
               }
               if (primeEnter <= numberOfPrimes)
               {
                   mySW.WriteLine(primeEnter);
                   primeCount++;
               }
               tester = false; //stiller tilbake boolen.

           }
           mySW.WriteLine();
           mySW.WriteLine();
           mySW.WriteLine("TOTAL NUMBER OF PRIME NUMBERS CALCULATED: " + primeCount);
           mySW.Dispose();
           mySW.Close();
           return path;
       }

       private string CalcOne(string[] startNumber)
       {
           uint primeCount = 0;
               string path = @"C:\primeresult.txt";
           System.IO.StreamWriter mySW = new System.IO.StreamWriter(path, false);
           double primeEnter = Convert.ToDouble(startNumber[0]);
           int numberOfPrimes = Convert.ToInt32(startNumber[1]); //numberOfPrimes = antall programmet skal finne.
           if (primeEnter <= 3)
           {
               mySW.WriteLine("2");
               mySW.WriteLine("3");
               primeEnter = 4;
               primeCount += 2;
           }
           primeEnter -= 1;
           bool tester = false; //Hvis tester = true så er det et primtall.
           for (ushort i = 0; primeCount < numberOfPrimes; i++) //egentlig hele programmet her. Det repeteres til du finner "numberOfPrimes" primtall.
           {

               while (tester == false) //mens det ikke er et primtall
               {
                   primeEnter++; //legg til én og prøv igjen. Dette er grunnen for at jeg la til (-1) i linje 17.
                   tester = IsPrime(primeEnter); //denne returnerer true hvis den finner at det er et primtall
               }
               if (primeCount <= numberOfPrimes)
               {
                   mySW.WriteLine(primeEnter);
                   primeCount++;
               }
               tester = false; //stiller tilbake boolen.

           }
           mySW.WriteLine();
           mySW.WriteLine();
           mySW.WriteLine("TOTAL NUMBER OF PRIME NUMBERS CALCULATED: " + primeCount);
           mySW.Dispose();
           mySW.Close();
           return path;
       }

 

 

 

AKTUELL FUNKSJON

 

 

        private string CalcBulks(string[] startNumber)
       {
           int bulkNumber = (Convert.ToInt32(startNumber[3]));
           int bulksCount = 0;
           int bulkSize = Convert.ToInt32(startNumber[2]);
           while(bulksCount < bulkNumber)
           {
               string path = @"C:\PrimeResultBulksOf" + startNumber[2] + @"BulkNumber" + Convert.ToString(bulksCount + 1) + ".txt";
               uint primeCount = 0;
               System.IO.StreamWriter mySW = new System.IO.StreamWriter(path);
               double primeEnter = Convert.ToDouble(startNumber[0]); //numberOfPrimes = antall programmet skal finne.
               if (primeEnter <= 3)
               {
                   mySW.WriteLine("2");
                   mySW.WriteLine("3");
                   primeEnter = 4;
                   primeCount += 2;
               }
               primeEnter -= 1;
               bool tester = false; //Hvis tester = true så er det et primtall.
               for (ushort i = 0; primeCount < bulkNumber; i++) //egentlig hele programmet her. Det repeteres til du finner "numberOfPrimes" primtall.
               {

                   while (tester == false) //mens det ikke er et primtall
                   {
                       primeEnter++; //legg til én og prøv igjen. Dette er grunnen for at jeg la til (-1) i linje 17.
                       tester = IsPrime(primeEnter); //denne returnerer true hvis den finner at det er et primtall
                   }
                   if (primeCount <= bulkNumber)
                   {
                       mySW.WriteLine(primeEnter);
                       primeCount++;
                   }
                   tester = false; //stiller tilbake boolen.
                   bulksCount++;
                   mySW.WriteLine();
                   mySW.WriteLine();
                   mySW.WriteLine("TOTAL NUMBER OF PRIME NUMBERS CALCULATED: " + primeCount);
                   mySW.Dispose();
                   mySW.Close();
               }


           }
           return @"C:\PrimeResult(...) files";
       }

 

 

 

KODE ETTER AKTUELL FUNKSJON

 

 

       static bool IsPrime (double primeTester)
       {
           uint squareRt = Convert.ToUInt32(Math.Ceiling(Math.Sqrt(primeTester))); 
           uint i = 2; //denne skal primeTester deles på. Om det kommer ut at den deles uten noen desimalplasser, finner programmet ut at det ikke er et primtall.
           while (i <= squareRt) //hvis i er større enn squareRt er i et primtall.
           {
               if (primeTester % i == 0) //altså, primeTester er ikke et primtall
               {
                   return false;
               }
               i++; //ellers legger man til 1 og prøver igjen.
           }
           return true;

       }

       private void checkBox1_CheckedChanged(object sender, EventArgs e)
       {
           if (bulks.Checked != true)
           {
               if (checkBox1.Text == "Number of primes instead")
               {
                   checkBox1.Text = "Last number to check instead";
                   label2.Text = "Enter number of primes to check:";
               }
               else
               {
                   checkBox1.Text = "Number of primes instead";
                   label2.Text = "  Enter last number to check:";
               }
           }
       }

       private void bulks_CheckedChanged(object sender, EventArgs e)
       {
           if (bulks.Checked == true)
           {
               checkBox1.Text = "Number of primes (LOCKED)";
               label2.Text = "Enter number of primes to check:";
               NumberOf.Text = "DON'T USE THIS BOX";
           }
           else
           {
               if (checkBox1.Checked == true)
               {
                   NumberOf.Text = "";
                   checkBox1.Text = "Last number to check instead";
                   label2.Text = "Enter number of primes to check:";
               }
               else
               {
                   NumberOf.Text = "";
                   checkBox1.Text = "Number of primes instead";
                   label2.Text = "  Enter last number to check:";
               }
           }
       }
   }
}

 

 

 

Får feilen "ObjectDisposedException was unhandled," "Cannot write to a closed TextWriter."

 

Noen som vet hva jeg har gjort galt?

Lenke til kommentar
Videoannonse
Annonse

Du sier ikke hvor det skjer, men det ser ut som det er frdi du lukker StreamWriter'en din inni en løkke i CalcBulks. Neste iterasjon som prøver å skrive til den etter den er lukket feiler.

 

Det er ikke nødvendig å kalle både Dispose() og Close() heller, Dispose vil rydde opp og lukke for deg, det er det den er til. Close() etter Dispose() vil ikke gjøre noe som helst.

 

Det finnes også en egen konstruksjon i C# som er designet akkurat for å unngå problemet du har her. Using-nøkkelordet tar en variabel/deklarasjon og sørger for at Dispose() kjøres automatisk på den når kontrollen forlater blokken, uansett hvordan det skjer. Da er du garantert at den blir lukket, at den bare lukkes når koden inni blokken er ferdig og variablenen som deklareres er kun i scope innenfor using-blokken, slik at det er umulig å skrive til den etter den er lukket.

 

using(var writer = new StreamWriter(...)) {
.... kode som skriver
} // automatisk dispose

 

I ditt tilfelle ville jeg også injisert strømmen inn CalcBulks-metoden din, slik at du holder detaljene rundt hva det skrives til, og livssyklus-ting adskilt fra det som skjer i metoden.

 

private string CalcBulks(string[] startNumber, StreamWriter outStream) {
...
// ingen instansiering eller close/dispose her
}
// Så i koden som kaller

using(var outStream = new StreamWriter(...)) {
   CalcBulks(... , outStream)
} 

 

Uansett hvordan du gjør det, ikke kall close/dispose manuelt. Bruk using-konstruksjonen, så forsvinner denne problematikken av seg selv.

Endret av MailMan13
Lenke til kommentar

Takker mye for kommentarene. Prøver tester med using {} nå.

 

@mailman, i eksempel 2, hvorfor kaller du using etter slutten av metoden? Skal den ikke være inni? I.e.:

 

private void metode()
{
   int i = 0;
   while (i < 12)
   {
       using (var sw = new System.IO.StreamWriter(@"C:\fil.txt")
       {
           sw.WriteLine(i);
       }
   }
}

Endret av DarkLightA
Lenke til kommentar

Tror jammen at det kan være at programmet funker nå! :new_woot:

 

Men jeg må vente litt, bruker det akkuratt nå til å kalkulere de første 25.000.000 primtallene.. Er på 11.000.000 nå :tease:

 

Kjekt med programmering synes jeg, men jeg har ikke funnet en god tutorial ennå. Vet dere om noen?

 

---

 

Og jeg beklager at jeg ikke spesifiserte hvilken linje jeg hadde problemer med. Jeg trodde jeg gjorde det, men noe må ha skjedd. Det var i linjen:

 System.IO.StreamWriter mySW = new System.IO.StreamWriter(path);

Lenke til kommentar

Den skal stå inni en metode ja, jeg er bare lat og gadd ikke skrive en hel metodedeklarasjon å putte den i.

 

Meningen var at using og variabeldeklarasjonen burde stå utenfor "CalcBulks", slik at den ikke trenger å bry seg om hva den skriver til. Det er ikke direkte relatert til feilen din, men det er ofte lurt å ikke gi for mye ansvar til hvert element i programmet ditt. Opprette og lukke en fil er ikke relatert til å regne primtall, så da gir det også mening å ikke ha det på samme sted i koden.

 

http://en.wikipedia.org/wiki/Separation_of_concerns

Lenke til kommentar

Ja, jeg vet. Dette er den første applikasjonen min, men jeg skal ha det i tankene i fremtiden.

 

Vil dette da fungere?

 

private void metodeEn()
{
   int i = 32;
   metodeTo(i);
}
private void metodeTo(int a)
{
using (var mySW = new System.IO.StreamWriter(@"C:\Output\Fil.txt")
   {
   mySW.WriteLine(a);
   }
}

 

Hvordan kan jeg lage en tredje metode som representerer det som skal være inni 'using'?

Endret av DarkLightA
Lenke til kommentar

Idé-dump:

 

private void metodeEn()
{
   string[] beskjed = new string[] {"Hei.", "Brukernavnet", "Mitt", "Er", "DarkLightA."}
   foreach (string i in beskjed)
   {
       metodeTo(i);
   }
}
private void metodeTo(int a)
{
   using (var mySW = new System.IO.StreamWriter(@"C:\Output\Fil.txt")
       {
           var[] swAndInputVar = new var[] { mySW, a };
           metodeTre(swAndInputVar);
       }
}
private void metodeTre(var[] inputVariables)
{
   inputVariables[0].WriteLine(inputVariables[1]);
}

 

Eller går jeg for langt i metode tre?

Lenke til kommentar

Ja. Bare tenk at objektet inne i using([objekt]) er kun gylding innenfor blokken. På slutten blir Dispose() kalt på objektet.

 

using oversettes til dette:

 

{
 var mySW = new System.IO.StreamWriter(@"C:\Output\Fil.txt");
 try
 {
   // kode...
 }
 finally
 {
   mySW.Dispose();
 }
}

Så du kan gjøre hva du vil innenfor using blokken.

Lenke til kommentar
  • 3 uker senere...

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...