Ich arbeite an einem Windows-Formular, um die UPC für Artikelnummern zu berechnen.
Ich habe erfolgreich eine erstellt, die jeweils eine Artikelnummer / UPC verarbeiten kann. Jetzt möchte ich sie erweitern und für mehrere Artikelnummern / UPCs ausführen.
Ich habe angefangen und versucht, eine Liste zu verwenden, aber ich bleibe immer stecken. Ich habe eine Helferklasse erstellt:
public class Codes
{
private string incrementedNumber;
private string checkDigit;
private string wholeNumber;
private string wholeCodeNumber;
private string itemNumber;
public Codes(string itemNumber, string incrementedNumber, string checkDigit, string wholeNumber, string wholeCodeNumber)
{
this.incrementedNumber = incrementedNumber;
this.checkDigit = checkDigit;
this.wholeNumber = wholeNumber;
this.wholeCodeNumber = wholeCodeNumber;
this.itemNumber = itemNumber;
}
public string ItemNumber
{
get { return itemNumber; }
set { itemNumber = value; }
}
public string IncrementedNumber
{
get { return incrementedNumber; }
set { incrementedNumber = value; }
}
public string CheckDigit
{
get { return checkDigit; }
set { checkDigit = value; }
}
public string WholeNumber
{
get { return wholeNumber; }
set { wholeNumber = value; }
}
public string WholeCodeNumber
{
get { return wholeCodeNumber; }
set { wholeCodeNumber = value; }
}
}
Dann habe ich mit meinem Code angefangen, aber das Problem ist, dass der Prozess inkrementell ist, das heißt, ich erhalte die Artikelnummer aus einer Rasteransicht über Kontrollkästchen und füge sie in die Liste ein. Dann hole ich den letzten UPC aus der Datenbank, entferne die Prüfziffer, erhöhe die Zahl um eins und füge sie in die Liste ein. Dann berechne ich die Prüfziffer für die neue Nummer und trage sie in die Liste ein. Und hier bekomme ich bereits eine Out of Memory-Ausnahme. Hier ist der Code, den ich bisher habe:
List<Codes> ItemNumberList = new List<Codes>();
private void buttonSearch2_Click(object sender, EventArgs e)
{
//Fill the datasets
this.immasterTableAdapter.FillByWildcard(this.alereDataSet.immaster, (textBox5.Text));
this.upccodeTableAdapter.FillByWildcard(this.hangtagDataSet.upccode, (textBox5.Text));
this.uPCTableAdapter.Fill(this.uPCDataSet.UPC);
string searchFor = textBox5.Text;
int results = 0;
DataRow[] returnedRows;
returnedRows = uPCDataSet.Tables["UPC"].Select("ItemNumber = '" + searchFor + "2'");
results = returnedRows.Length;
if (results > 0)
{
MessageBox.Show("This item number already exists!");
textBox5.Clear();
//clearGrids();
}
else
{
//textBox4.Text = dataGridView1.Rows[0].Cells[1].Value.ToString();
MessageBox.Show("Item number is unique.");
}
}
public void checkMarks()
{
for (int i = 0; i < dataGridView7.Rows.Count; i++)
{
if ((bool)dataGridView7.Rows[i].Cells[3].FormattedValue)
{
{
ItemNumberList.Add(new Codes(dataGridView7.Rows[i].Cells[0].Value.ToString(), "", "", "", ""));
}
}
}
}
public void multiValue1()
{
_value = uPCDataSet.UPC.Rows[uPCDataSet.UPC.Rows.Count - 1]["UPCNumber"].ToString();//get last UPC from database
_UPCNumber = _value.Substring(0, 11);//strip out the check-digit
_UPCNumberInc = Convert.ToInt64(_UPCNumber);//convert the value to a number
for (int i = 0; i < ItemNumberList.Count; i++)
{
_UPCNumberInc = _UPCNumberInc + 1;
_UPCNumberIncrement = Convert.ToString(_UPCNumberInc);//assign the incremented value to a new variable
ItemNumberList.Add(new Codes("", _UPCNumberIncrement, "", "", ""));//**here I get the OutOfMemoreyException**
}
for (int i = 0; i < ItemNumberList.Count; i++)
{
long chkDigitOdd;
long chkDigitEven;
long chkDigitSubtotal;
chkDigitOdd = Convert.ToInt64(_UPCNumberIncrement.Substring(0, 1)) + Convert.ToInt64(_UPCNumberIncrement.Substring(2, 1)) + Convert.ToInt64(_UPCNumberIncrement.Substring(4, 1)) + Convert.ToInt64(_UPCNumberIncrement.Substring(6, 1)) + Convert.ToInt64(_UPCNumberIncrement.Substring(8, 1)) + Convert.ToInt64(_UPCNumberIncrement.Substring(10, 1));
chkDigitOdd = (3 * chkDigitOdd);
chkDigitEven = Convert.ToInt64(_UPCNumberIncrement.Substring(1, 1)) + Convert.ToInt64(_UPCNumberIncrement.Substring(3, 1)) + Convert.ToInt64(_UPCNumberIncrement.Substring(5, 1)) + Convert.ToInt64(_UPCNumberIncrement.Substring(7, 1)) + Convert.ToInt64(_UPCNumberIncrement.Substring(9, 1));
chkDigitSubtotal = (300 - (chkDigitEven + chkDigitOdd));
_chkDigit = chkDigitSubtotal.ToString();
_chkDigit = _chkDigit.Substring(_chkDigit.Length - 1, 1);
ItemNumberList.Add(new Codes("", "",_chkDigit, "", ""));
}
Ist dies der richtige Weg, eine Liste zu verwenden, oder sollte ich einen anderen Weg einschlagen?
Code
Klasse) sind redundant und nichts als Lärm{ get; private set; }
würde wirklich ausreichen.Antworten:
Ich werde meinen Kommentar erweitern:
Eine schnelle Panne
Arrays sind gut, wenn Sie über eine feste Anzahl von Elementen verfügen , die sich wahrscheinlich nicht ändern, und nicht sequentiell darauf zugreifen möchten.
Verknüpfte Listen sind für schnelles Hinzufügen und Entfernen an beiden Enden optimiert, haben jedoch in der Mitte einen langsamen Zugriff.
Array-Listen (wie
List<T>
in C #!) Sind eine Mischung aus beidem, mit relativ schnellen Hinzufügungen und wahlfreiem Zugriff.List<T>
wird oft Ihre Sammlung sein, wenn Sie nicht sicher sind, was Sie verwenden sollen.So funktionieren Arrays
Die meisten Sprachen modellieren Arrays als zusammenhängende Daten im Speicher, von denen jedes Element dieselbe Größe hat. Nehmen wir an, wir hatten ein Array von
int
s (angezeigt als [Adresse: Wert], mit Dezimaladressen, weil ich faul bin)Jedes dieser Elemente ist eine 32-Bit-Ganzzahl, daher wissen wir, wie viel Speicherplatz es im Speicher einnimmt (32 Bit!). Und wir kennen die Speicheradresse des Zeigers auf das erste Element.
Es ist trivial einfach, den Wert eines anderen Elements in diesem Array zu ermitteln:
Nehmen wir an, unser erstes Element ist '0'. Wir wissen, dass unser zweites Element bei '32' (0 + (32 * 1)) und unser drittes Element bei 64 (0 + (32 * 2)) liegt.
Die Tatsache, dass wir all diese Werte nebeneinander speichern können, bedeutet, dass unser Array so kompakt wie möglich ist. Es bedeutet auch, dass alle unsere Elemente zusammen bleiben müssen, damit die Dinge weiter funktionieren!
Sobald wir ein Element hinzufügen oder entfernen, müssen wir alles andere aufnehmen und an eine neue Stelle im Speicher kopieren, um sicherzustellen, dass keine Lücken zwischen den Elementen vorhanden sind und alles genügend Platz hat. Dies kann sehr langsam sein , insbesondere wenn Sie dies jedes Mal tun , wenn Sie ein einzelnes Element hinzufügen möchten.
Verknüpfte Listen
Im Gegensatz zu Arrays müssen bei verknüpften Listen nicht alle Elemente im Speicher nebeneinander liegen. Sie bestehen aus Knoten, die die folgenden Informationen speichern:
Die Liste selbst enthält in den meisten Fällen einen Verweis auf den Kopf und den Schwanz (erster und letzter Knoten) und verfolgt manchmal ihre Größe.
Wenn Sie ein Element am Ende der Liste hinzufügen möchten, müssen Sie nur den Schwanz abrufen und ihn so ändern
Next
, dass er auf ein neues Element verweist,Node
das Ihren Wert enthält. Das Entfernen vom Ende ist ebenso einfach - dereferenzieren Sie einfach denNext
Wert des vorhergehenden Knotens.Wenn Sie ein
LinkedList<T>
Element mit 1000 Elementen haben und Element 500 möchten, gibt es leider keine einfache Möglichkeit, direkt zum 500. Element zu springen, wie dies bei einem Array der Fall ist. Sie müssen am Kopf beginnen und weiter zumNext
Knoten gehen, bis Sie dies 500 Mal getan haben.Aus diesem Grund ist das Hinzufügen und Entfernen von a
LinkedList<T>
schnell (wenn Sie an den Enden arbeiten), aber der Zugriff auf die Mitte ist langsam.Bearbeiten : Brian weist in den Kommentaren darauf hin, dass verknüpfte Listen das Risiko haben, einen Seitenfehler zu verursachen, da sie nicht im zusammenhängenden Speicher gespeichert werden. Dies kann schwierig zu bewerten sein und dazu führen, dass verknüpfte Listen aufgrund ihrer zeitlichen Komplexität sogar etwas langsamer ablaufen als erwartet.
Beste aus beiden Welten
List<T>
Kompromisse für beideT[]
undLinkedList<T>
und bietet eine Lösung, die in den meisten Situationen relativ schnell und einfach zu bedienen ist.Intern
List<T>
ist ein Array! Es muss beim Ändern der Größe immer noch durch die Rahmen springen, um seine Elemente zu kopieren, aber es zieht ein paar nette Tricks.Wenn Sie ein einzelnes Element hinzufügen, wird das Array normalerweise nicht kopiert.
List<T>
Stellt sicher, dass immer genügend Platz für weitere Elemente vorhanden ist. Anstatt ein neues internes Array mit nur einem neuen Element zuzuweisen, wird ein neues Array mit mehreren neuen Elementen zugewiesen (oft doppelt so viele wie derzeit!).Kopiervorgänge sind teuer.
List<T>
Reduzieren Sie sie daher so weit wie möglich, und ermöglichen Sie dennoch einen schnellen Direktzugriff. Als Nebeneffekt wird möglicherweise etwas mehr Speicherplatz verschwendet als bei einem direkten Array oder einer verknüpften Liste, aber in der Regel lohnt sich der Kompromiss.TL; DR
Verwenden Sie
List<T>
. Es ist normalerweise das, was Sie wollen, und es scheint in dieser Situation (in der Sie .Add () aufrufen) für Sie richtig zu sein. Wenn Sie sich nicht sicher sind, was Sie brauchen,List<T>
ist dies ein guter Anfang.Arrays eignen sich gut für leistungsstarke "Ich weiß, ich brauche genau X-Elemente" -Dinge. Alternativ sind sie nützlich für schnelle, einmalige "Ich muss diese X-Dinge, die ich bereits definiert habe, gruppieren, damit ich über sie eine Schleife erstellen kann" -Strukturen.
Es gibt eine Reihe weiterer Sammelklassen.
Stack<T>
ist wie eine verknüpfte Liste, die nur von oben funktioniert.Queue<T>
arbeitet als First-In-First-Out-Liste.Dictionary<T, U>
ist eine ungeordnete assoziative Zuordnung zwischen Schlüsseln und Werten. Spielen Sie mit ihnen und lernen Sie deren Stärken und Schwächen kennen. Sie können Ihre Algorithmen machen oder brechen.quelle
int
Angabe der Anzahl verwendbarer Elemente Vorteile bringen . Unter anderem ist es möglich, mehrere Elemente gleichzeitig von einem Array in ein anderes zu kopieren. Für das Kopieren zwischen Listen müssen die Elemente jedoch in der Regel einzeln verarbeitet werden. Darüber hinaus können Array-Elementeref
an Dinge wie übergeben werdenInterlocked.CompareExchange
, während Listenelemente dies nicht können.List<>
sie unter der Haube funktionieren.(index+first)%length
.Während die Antwort von KChaloux großartig ist, möchte ich auf eine andere Überlegung hinweisen: Ist
List<T>
viel leistungsfähiger als ein Array. Die Methoden vonList<T>
sind unter vielen Umständen sehr nützlich - ein Array verfügt nicht über diese Methoden, und Sie müssen möglicherweise viel Zeit aufwenden, um Problemumgehungen zu implementieren.Aus entwicklungspolitischer Sicht verwende ich daher fast immer,
List<T>
da zusätzliche Anforderungen oft viel einfacher zu implementieren sind, wenn Sie a verwendenList<T>
.Dies führt zu einem letzten Problem: Mein Code (ich weiß nicht, wie es bei Ihnen aussieht) enthält 90%
List<T>
, sodass Arrays nicht wirklich passen. Wenn ich sie weitergebe, muss ich ihre.toList()
Methode aufrufen und sie in eine Liste konvertieren - dies ist ärgerlich und so langsam, dass jeglicher Leistungsgewinn durch die Verwendung eines Arrays verloren geht.quelle
Niemand erwähnte diesen Teil jedoch: "Und hier bekomme ich bereits eine Ausnahmebedingung wegen unzureichendem Speicher." Welches ist ganz auf
Es ist klar, warum. Ich weiß nicht, ob Sie einer anderen Liste hinzufügen
ItemNumberList.Count
wollten oder nur als Variable vor der Schleife speichern sollten , um das gewünschte Ergebnis zu erzielen, aber das ist einfach kaputt.Programmers.SE steht für "... Interesse an konzeptionellen Fragen zur Softwareentwicklung ..." und die anderen Antworten behandelten es als solche. Versuchen Sie stattdessen http://codereview.stackexchange.com , wo diese Frage passen würde. Aber selbst dort ist es schrecklich, da wir nur davon ausgehen können, dass dieser Code bei beginnt, bei
_Click
dem kein Anruf erfolgt,multiValue1
bei dem Sie sagen, dass der Fehler auftritt.quelle