for schneller als foreach?
-
Ich nehme schon mal nicht ohne konkreten Grund das weniger schöne. Ich kann mit deinem Programm nicht viel anfangen, weil ich selber nur die 2005 beta habe und das in keinster Weise repräsentativ ist.
Außerdem ist die Messung mit DateTime nicht aussagekräftig in einer inneren Schleife, weil das bei mir nicht mal in Millisekunden (!!) - Genauigkeit arbeitet. Und das in ner inneren Schleife.Ich schreib selber mal was kleines zam, aber wie gesagt, ich hab nur ne beta und glaube dann selber nicht an die Aussagekräftigkeit.
P.S. ich hab das Ende deines Programms nicht abgewartet.
EDIT: Ich halte die Beta Ergebnisse btw. deshalb nicht für Aussagekräftig, weil man damit nur Debug-Builds erstellen kann und keiner weiß, was der aus nem foreach jetzt macht.
-
ohne einen flamthread draus machen zu wollen...
man sollte in sachen performance nich allein ueber
die "nackte" sprache nachdenken. nach dem motto:
assembler < c < c++ < c#
(c++ ist schneller als c#, c schneller als c++, ass schneller als c).das gilt wohl fuer kleine programme. grade bei grossen programmen
laeuft man oft gefahr den ueberblick zu verlieren.
dann mag eine einzelne anweisung geschrieben in assembler schneller
sein. das "grosse ganze" assembler programm aber langsamer als
ein vergleichbares in c++.grade bei c# denke ich, dass alles besser auf einander abgestimmt ist.
das framework ist aus einem guss. bei c++ muesstest du um vergleichbare
programme zu schreiben auf eine vielzahl unterschiedlicher libs
zurueckgreifen. ob das ganze noch so gut zusammenlaeuft?solltest du dir mal gedanken drueber machen.
bitte kein flame beginnen :). ich sage jetzt nicht c# ist besser
als assembler. nur bitte nicht immer die aussagen der form:
"mein assembler programm braucht fuer schleife x y rechentakte
weniger -> alles wird schneller sein".
-
@Optimizer :
das ergeibnis sieht so aus:..... 500 546,875 484,375 546,875 500 546,875 484,375 546,875 500 531,25 500 546,875 500 546,875 484,375 546,875 500 546,875 484,375 546,875 500 531,25 500 546,875 484,375 546,875 500 546,875 500 531,25 515,625 531,25 500 531,25 500 546,875 500 531,25 515,625 531,25 500 546,875 500 531,25 500 546,875 500 531,25 500 546,875 500 546,875 500 546,875 484,375 546,875 484,375 546,875 500 546,875 484,375 546,875 500 546,875 500 546,875 484,375 546,875 484,375 546,875 500 546,875 500 546,875 484,375 546,875 500 531,25 500 546,875 500 546,875 500 531,25 500 546,875 484,375 546,875 500 546,875 500 531,25 500 531,25 500 546,875 500 546,875 500 531,25 500 546,875 500 531,25 500 546,875 484,375 562,5 500 531,25 Durchschnitt for: 513,59375 Durchschnitt foreach: 567,96875 Geschwindigkeitsvorteil von for: 5437,5
Sicherlich birgt die Messmethode über DateTime Ungenauigkeiten. Diese Ungenauigkeiten gelten aber für beide (for und foreach). Deshalb habe ich die Mesungen auch so geschachtelt angeordnet. Das ist ein plausibler Vergleich. Du kannst mir erzählen was du willst. Das Ergebnis kannst du nicht wegdiskutieren.
-
Um mal was zum Thema beizutragen. Prinzipiell ist for immer schneller als foreach weil bei foreach ja auf alle Fälle Enumerator Objekte erstellt werden und auch benutzt werden. Und foreach wird meiner Meinung nach nie zu ner for Schleife optimiert(gerade aus dem Grund weil sie anders funktioniert), aber lass mich gerne was besseren belehren. Ist zwar Offtopic aber benutze auf Arbeit nen C Compiler von Tasking für nen TC1796(ist nen µC von Infineon) und was der optimiert ist unnormal, bin echt beeindruckt was der einen abnimmt an optimierungsarbeit
Um aber wieder zum Thema zurückzukommen, irgendwo hab ich auch mal nen Satz von nem Entwickler des C# Compilers gelesen das man nicht versuchen sollte den Compiler was vorabzugreifen an Optimierungen, des geht meist schief.
-
Sicherlich birgt die Messmethode über DateTime Ungenauigkeiten. Diese Ungenauigkeiten gelten aber für beide (for und foreach). Deshalb habe ich die Mesungen auch so geschachtelt angeordnet. Das ist ein plausibler Vergleich. Du kannst mir erzählen was du willst. Das Ergebnis kannst du nicht wegdiskutieren.
Oh doch, das kann ich. Das die Ungenauigkeit für beide gilt, ist kein Argument. Der eine kann öfters 1,3ms pro Durchlauf kriegen (bei mir die kleinste Einheit), der andere öfters 0. Die Messung ist -sorry- Schrott.
Außerdem sind diese Tests ziemlich witzlos aus ganz anderen Gründen noch. Ich habe gerade selber was geschrieben und was interessantes festgestellt.
using System; using System.Runtime.InteropServices; class Test { [DllImport("kernel32.dll")] private extern static void QueryPerformanceCounter(out long currentTime); [DllImport("kernel32.dll")] private extern static void QueryPerformanceFrequency(out long frequency); private static void Main() { int[] x = new int[100000000]; { init(x); int sum = 0; long start, end; QueryPerformanceCounter(out start); foreach( int i in x ) sum += i; QueryPerformanceCounter(out end); Console.WriteLine("Summe 1: " + sum); Console.WriteLine("Zeit 1: " + (end - start)); } { init(x); int sum = 0; long start, end; QueryPerformanceCounter(out start); for( int i = 0; i < x.Length; ++i ) sum += x[i]; QueryPerformanceCounter(out end); Console.WriteLine("Summe 2: " + sum); Console.WriteLine("Zeit 2: " + (end - start)); } Console.In.Read(); } private static void init(int[] x) { Random rand = new Random(); for( int i = 0; i < x.Length; ++i ) x[i] = rand.Next(50); } }
Nach meinem Ergebnis ist foreach fast 10% schneller. Aber wie aussagekräftig ist das. Man vertausche die Reihenfolge und auf einmal ist for 10% schneller. Volkard hat mal irgendwo erwähnt, dass das Betriebssystem "Langrechnern" irgendwann weniger Resourcen gibt.
Vertausch mal bei deinem Test die Reihenfolge... würd mich interessieren. Aber die Messung kannst du eh vergessen über DateTime, du solltest dein Programm echt noch mal umschreiben.
Jetzt haben wirs eh nur für valuetype-arrays getestet. Ein Szenario von tausend. Bei Ref-type arrays kanns wieder anders sein. Bei LinkedList wieder anders.Wir kriegen auf die Weise nix zusammen. Weder mit der Messung über DateTime noch mit dem (nicht-)umdrehen des Ergebnisses durch Umdrehen der Messreihenfolge.
Ich pack mal, sobald 2005 final ist den Disassembler raus. Meine Theorie ist eh, dass beide Schleifen den selben Code generieren, wahrscheinlich schon auf MSIL-Ebene.
-
entelechie schrieb:
..
man sollte in sachen performance nich allein ueber
die "nackte" sprache nachdenken. nach dem motto:
assembler < c < c++ < c#
(c++ ist schneller als c#, c schneller als c++, ass schneller als c).das gilt wohl fuer kleine programme. grade bei grossen programmen
laeuft man oft gefahr den ueberblick zu verlieren.
dann mag eine einzelne anweisung geschrieben in assembler schneller
sein. das "grosse ganze" assembler programm aber langsamer als
ein vergleichbares in c++.grade bei c# denke ich, dass alles besser auf einander abgestimmt ist.
das framework ist aus einem guss. bei c++ muesstest du um vergleichbare
programme zu schreiben auf eine vielzahl unterschiedlicher libs
zurueckgreifen. ob das ganze noch so gut zusammenlaeuft?solltest du dir mal gedanken drueber machen.
bitte kein flame beginnen :). ich sage jetzt nicht c# ist besser
als assembler. nur bitte nicht immer die aussagen der form:
"mein assembler programm braucht fuer schleife x y rechentakte
weniger -> alles wird schneller sein".natürlich...da wag ich dir nicht zu wiedersprechen. Ist alles zutreffend. Ich hab aber vom .Net gesprochen und nicht von C#.
du kannst mit C# sehr wohl schnellen code shreiben aber dafür musst du mit unsafe .Net verlassen.
Und wann braucht man schon wirklich schnellen code? Treiber vielleicht oder so...
Die meisten Firmen sind froh das sie ihr Programm fertig kriegen. Da wird hier rumgebastellt und da geflickt. Von Perfomance kann keine rede sein. Das hängt auch ganz klar vom code ab.Irgendwo hab ich mal gelesen das man 20% Geschwindigkeitssteigerung braucht um körperlich einen Unterschied zu merken.
-
Talla schrieb:
Um mal was zum Thema beizutragen. Prinzipiell ist for immer schneller als foreach weil bei foreach ja auf alle Fälle Enumerator Objekte erstellt werden und auch benutzt werden.
Ähm ne. Hast du den Compiler geschrieben? Bei ner LinkedList brauchst du auch bei for nen Enumerator (außer du machst es mega-ineffizient über Index). Und bei einem Array wird foreach schon nichts anderes machen als for( int i = 0; i < array.Length; ++i )
Falls das der Compiler nicht schaffen sollte, wäre es zu traurig, das würde ja sogar ich auf die Reihe kriegen, foreach nach for zu übersetzen.Und foreach wird meiner Meinung nach nie zu ner for Schleife optimiert(gerade aus dem Grund weil sie anders funktioniert),
Warum ist das umwandeln zu einer for-Schleife "Optimierung" und inwiefern funktioniert eine vollständige Iteration über for anders als foreach?
Wenn du mir 2min Zeit gibst, schreib ich dir ein Programm, dass foreach in for umwandelt.
-
natürlich...da wag ich dir nicht zu wiedersprechen. Ist alles zutreffend. Ich hab aber vom .Net gesprochen und nicht von C#.
du kannst mit C# sehr wohl schnellen code shreiben aber dafür musst du mit unsafe .Net verlassen.Falsch. Um die zusätzliche Ausdrucksfähigkeit von unsafe Code zu deinem Vorteil nutzen zu können, musst du echt was drauf haben, das schaffen wir beide mit Sicherheit nicht.
Ich unterstelle dir mal böse, dass in deinem Hinterkopf immer noch was mit "managed Code" in Zusammenhang mit "interpretieren" rumspukt?
"managed Code" liegt als Native Code im RAM und ist auch genauso optimiert.
Und noch eine winzige Kleinigkeit: du verlässt mit unsafe Code nicht .Net! unsafe Code ist immer noch managed Code und wird genauso JIT-compiliert. Unsafe Code ist nur nicht "veryfiable". Das ist ein ganz bedeutender Unterschied.Irgendwo hab ich mal gelesen das man 20% Geschwindigkeitssteigerung braucht um körperlich einen Unterschied zu merken.
Ahhhhhhhhhhhhjaaaaaaaaaaa?! Ich kann nicht mal erraten, was das bedeuten soll.
-
Tach,
hm,
Ergebnis von deinem Programm:Summe 1: -1845137419 Zeit 1: 103927728 Summe 2: -1844790070 Zeit 2: 2573163
demnach ist die for-Schleife, wie ich schon sagte, schneller.
-
eigentlich muss man sagen....foreach wurde wohl für Array eingeführt...also warum auch nicht benutzen??? ist doch viel einfacher, übersichtlicher und auf einem WinXP Rechner mit 2GHz -> wieviel Elemente braucht wohl ein Array um mal einen Unterschied von 5 sec zwischen den beiden Schleifen zu spüren?
-
AndreasW schrieb:
Tach,
hm,
Ergebnis von deinem Programm:Summe 1: -1845137419 Zeit 1: 103.927.728 Summe 2: -1844790070 Zeit 2: 2.573.163
demnach ist die for-Schleife, wie ich schon sagte, schneller.
50mal schneller?
Kann ich bei mir nicht nachvollziehen. Bei mir ist immer das erste schneller. Ich halte von diesem Test eh nichts (hab ich ja vorher schon angekündigt).
Und du willst aber wohl auch nicht ernsthaft wegdiskutieren, dass es super einfach ist, ein foreach auf ein array in ein äquivalentes for umzuwandeln oder? Ich bin mir sicher, der Compiler generiert den selben Code.Und bei 50mal hast du dich jetzt bestimmt vertippt, oder?
-
Optimizer schrieb:
natürlich...da wag ich dir nicht zu wiedersprechen. Ist alles zutreffend. Ich hab aber vom .Net gesprochen und nicht von C#.
du kannst mit C# sehr wohl schnellen code shreiben aber dafür musst du mit unsafe .Net verlassen.Falsch. Um die zusätzliche Ausdrucksfähigkeit von unsafe Code zu deinem Vorteil nutzen zu können, musst du echt was drauf haben, das schaffen wir beide mit Sicherheit nicht.
Ich unterstelle dir mal böse, dass in deinem Hinterkopf immer noch was mit "managed Code" in Zusammenhang mit "interpretieren" rumspukt?
"managed Code" liegt als Native Code im RAM und ist auch genauso optimiert.
Und noch eine winzige Kleinigkeit: du verlässt mit unsafe Code nicht .Net! unsafe Code ist immer noch managed Code und wird genauso JIT-compiliert. Unsafe Code ist nur nicht "veryfiable". Das ist ein ganz bedeutender Unterschied.ist klar, es ist ganz normaler MISL-Code aber trotzdem verläßt du .Net oder du gehst dran vorbei oder wie du das nennen willst. Im unsafe-Mode kannst du z.B. direkt auf den Speicher zugreifen. Und da musst du nun mal leider an .Net vorbei. Du gist deine Speicheranfragen dann nicht mehr weiter sondern direkt rein. Machst du da nen fehler haust du nicht nur dein Programm sondern auch das ganze .Net weg.
Wenn du Hardwarenah programmieren willst dann kommst du an unsafe nicht vorbei, ist tatsache!
Optimizer schrieb:
Irgendwo hab ich mal gelesen das man 20% Geschwindigkeitssteigerung braucht um körperlich einen Unterschied zu merken.
Ahhhhhhhhhhhhjaaaaaaaaaaa?! Ich kann nicht mal erraten, was das bedeuten soll.
was verstehst du daran nicht? du fährst mit 80 km/h. Leichte geschwindigkeittsteigerung bemerkst du erst ab ca. 100. das mein ich.
Hast du 2GHz CPU dann frühestens bei 2,400Ghz umsteigen. Weil du alles andere physisch nicht merkst.
-
oh, war wohl ein kopierfehler:
hier eine andere Messung:
Summe 1: -1845122201 Zeit 1: 2777047 Summe 2: -1844810424 Zeit 2: 2553207
und weil es so schön ist einmal umgekehrt:
Summe 2: -1845073467 Zeit 2: 2537453 Summe 1: -1845054705 Zeit 1: 2545909
ist aber auch egal.
Wir haben bei uns große Datenmengen im Umlauf. Wir müssen hier und da auch programmtechnisch Daten zusammenfügen, wobei wir nicht um doppelschleifen herumkommen. Meine Erfahrung hat gezeigt, das eine for-Schleife sich auch in der Praxis als schneller erweist.Mein Beispiel sollte ja nicht zeigen wieviel % for schneller ist, sondern das for tendentiell schneller ist. Das ist Fakt.
-
ist klar, es ist ganz normaler MISL-Code aber trotzdem verläßt du .Net oder du gehst dran vorbei oder wie du das nennen willst.
Nene, das ist ziemlicher Unsinn. Du verlässt .Net mit unsafe Code nicht, das ist Fakt.
Im unsafe-Mode kannst du z.B. direkt auf den Speicher zugreifen. Und da musst du nun mal leider an .Net vorbei. Du gist deine Speicheranfragen dann nicht mehr weiter sondern direkt rein. Machst du da nen fehler haust du nicht nur dein Programm sondern auch das ganze .Net weg.
Wenn du Hardwarenah programmieren willst dann kommst du an unsafe nicht vorbei, ist tatsache!
Das ist doch Blödsinn. Was heißt bitte "direkt" auf den Speicher zugreifen??
Du kannst die Adresse holen toll, das darfst du halt sonst einfach nur aus Sprach-Gründen nicht (weil der GC Objekte verschiebt und weil mit Addressen zu rechnen schief gehen kann).
Da ist nix mit "direkt auf den Speicher zugreifen". Du kannst im veryfiable Code nur keine Fehler machen, im unsafe Code schon. Außerdem hast du im veryfiable Code auf dem managed Heap eine Indirektion mehr. Und das ist alles. Da sind keine Checks drin oder sonst was, alleine die Sprache stellt sicher, dass du mit den Addressen keine Fehler machen kannst.Wenn du im veryfiable Code fehler machen könntest (wenn die Sprachmittel das zuließen), würdest du auch "das ganze .Net weghauen", was wohl soviel heißen soll wie, dass du eine acces violation kriegst.
Das hat auch mit hardwarenah programmieren nicht wirklich was zu tun, genauso wie C++ nicht wirklich hardwarenah ist. Nen Speicher hat jeder Computer, unsafe Code ist kaum mehr low-level als managed Code, du hast nur weniger Prüfungen und keinen GC.
was verstehst du daran nicht? du fährst mit 80 km/h. Leichte geschwindigkeittsteigerung bemerkst du erst ab ca. 100. das mein ich.
Hast du 2GHz CPU dann frühestens bei 2,400Ghz umsteigen. Weil du alles andere physisch nicht merkst.Was hat das mit dem Programm zu tun? Wieso musss mein Programm 20% schneller werden, damit ich was merke? Davon abgesehen sind so generelle Aussagen wie "Programm x ist 20% schneller als Programm y" eh nicht tragbar. Da muss man eine bestimmte Aufgabe spezifizieren, und und und. In der innersten und kritischsten Schleife sind 20% definitiv nicht tragbar.
-
@AndreasW: Kennst du die Messeinheit? Auf meinem Prozessor ungefähr ne 4millionstel Sekunde... Das kann an so vielen Faktoren liegen. Wie gesagt, ich zweifle mein Programm selber an, aber zumindest sehe ich eher die Tendenz, dass die Teile gleich schnell sind. Von "fakt, dass for schneller ist" kann man IMHO hier nicht sprechen.
Aber ist ja auch egal. Wir wissen ja beide, dass die Performance eines Programms nicht an einer for(each) Schleife hängt.
Ich würde aber grundsätzlich foreach nehmen und nur wenn es sich echt als Flaschenhals erweist, testen ob for schneller ist. Du darfst auch nicht vergessen, dass wir hier einen _sehr_ speziellen und beschränkten Fall hier betrachtet haben.
-
Kennst du die Messeinheit? Auf meinem Prozessor ungefähr ne 4millionstel Sekunde...
joh, kenn ich von c++.
Das kann an so vielen Faktoren liegen
sicherlich.
Aber ist ja auch egal. Wir wissen ja beide, dass die Performance eines Programms nicht an einer for(each) Schleife hängt.
klar, wer schleifen vermeiden kann, sollte das tun. Wenn man bei einem so großen array mit einer Schleife ran muss, würde ich das array eh partitionieren, sofern man nicht alle Werte benötigt.
Ich würde aber grundsätzlich foreach nehmen und nur wenn es sich echt als Flaschenhals erweist, testen ob for schneller ist.
naja, für mich gibt es da ein Kriterium mehr. Wenn ich den Index eines Wertes brauche oder Items aus einem Array lösche oder einfüge, würde ich immer eine for-Schleife nehmen.
Wenn ich nicht auf den Index angewiesen bin und vielleicht nur ein Array auslesen will, nehme ich foreach. Ist leserlicher.Aber das kann ja auch Geschmackssache sein...
-
Nene, das ist ziemlicher Unsinn. Du verlässt .Net mit unsafe Code nicht, das ist Fakt.
hauptfunktion von .Net -> Die Resoucen vom System zur verfügung stellen.
Besorge ich mir z.B. Speicher besorgen ich mir somit selber Resoucen. darum gibts ja auch z.B. das schlüsselwort fixed damit .Net nicht unerlaubt Daten im Speicher verschiebt auf die du vielleicht in unsafe zugreifen möchtest.
und für mich ist das .Net verlassen weil .Net "nicht mehr weis" was du tust.aber da kann man ja auch natürlich drüberstreiten
auch was hardwarenach ist kann man drüber streiten. Tatsache ist das MS selbst sagt: unsafe bei Leistungskritischer Code
Was hat das mit dem Programm zu tun? Wieso musss mein Programm 20% schneller werden, damit ich was merke? Davon abgesehen sind so generelle Aussagen wie "Programm x ist 20% schneller als Programm y" eh nicht tragbar. Da muss man eine bestimmte Aufgabe spezifizieren, und und und. In der innersten und kritischsten Schleife sind 20% definitiv nicht tragbar.
weil der Mensch zu langsam ist um kleine geschwindigkeitsunterschiede zu merken. Die meisten Programme verbringen doch sowieso mehr Zeit damit auf den User zu warten als was zu tun.
übrigens hab ich nicht gesagt das die schleife 20% langsammer sein muss...welche schleife auch immer.
ich hab geschrieben das du schon 20% leistungsunterschied brauchst um was zu merken.
Jetzt vergleich das aber nicht mit Videoencoding oder sowas -> das hat nix mehr mit dem Menschen zutun, da gehts um reine Rechenpower.
-
auch was hardwarenach ist kann man drüber streiten. Tatsache ist das MS selbst sagt: unsafe bei Leistungskritischer Code
Microsoft sagt aber nicht, dass man dazu auch was drauf haben muss, um das dann besser zu machen als der Compiler und der GC.
Es gibt dort viele Fallstricke, vielleicht übersieht man Optimierungen, die der JITer bei veryfiable Code ohne zu zögern gemacht hätte, sich aber hier nicht traut.
Vielleicht wird alles noch langsamer, weil das Allokieren auf dem unmanaged Heap wesentlich langsamer ist? Vielleicht hätte es der managed Heap besser gemacht?Nene, da können wir beide nicht viel mit rausholen, aber ich weiß das wenigstens noch, mit dem Gedanken solltest du dich auch mal anfreunden. Das heißt ja nicht, dass ich es nicht mal probieren würde, wenn ich ganz genau Bescheid wüsste, dass eine kleine Drecksfunktion mir die ganze Performance ruiniert, aber so extrem ist mir das noch nicht untergekommen.
Grundlos nutze ich das nicht, denn man zahlt dafür definitiv auch seinen Preis (z.B. benötigt man eine höhere Sicherheitserlaubnis, um den Code auszuführen).
Und ich bleibe definitiv dabei, dass man .Net nicht damit verlässt.
hauptfunktion von .Net -> Die Resoucen vom System zur verfügung stellen.
Besorge ich mir z.B. Speicher besorgen ich mir somit selber Resoucen.Nein, wie kommst du denn da drauf? Du benutzt immer noch nen Allokator von .Net mit fixed benutzt du halt einen, der dir auf dem unmanaged Heap Speicher zur Verfügung stellt.
weil der Mensch zu langsam ist um kleine geschwindigkeitsunterschiede zu merken. Die meisten Programme verbringen doch sowieso mehr Zeit damit auf den User zu warten als was zu tun.
übrigens hab ich nicht gesagt das die schleife 20% langsammer sein muss...welche schleife auch immer.
ich hab geschrieben das du schon 20% leistungsunterschied brauchst um was zu merken.
Jetzt vergleich das aber nicht mit Videoencoding oder sowas -> das hat nix mehr mit dem Menschen zutun, da gehts um reine Rechenpower.Das ist doch ne Milchmädchenaussage. Nimm mir 20% Frames von FarCry weg und ich werd sicher nicht sagen, dass ich keinen Unterschied merke. Du nennst viel zu leichtfertig irgendwelche konkreten Zahlen, das ist nicht sehr sinnvoll.
-
Ich habe die Geschwindigkeit jetzt auch mal getestet, allerdings nur mit DateTime und bei mir war die for-Schleife ca. doppelt so schnell wie die foreach und beim Test mit unsafe gab es überhaupt keine Abweichung zu den Tests ohne unsafe.
-
Wie sieht es eigentlich bei Enums aus? Mein Versuch ein Enum mit einer for-Schleife zu durchlaufen ist wesentlich langsamer als die Alternative mit der foreach-Schleife, aber vielleicht lag es auch nur an meinem Ansatz.
class Class1 { private enum Chars { a = 97, b, c, d, e, f ,g ,h ,i ,j , k, l ,m ,n ,o ,p ,q ,r ,s ,t, u, v, w, x, y, z, A = 65, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, zero = 48, one, two, three, four, five, six, seven, eight, nine, ae = 228, oe = 246, ue = 252, AE = 196, OE = 214, UE = 220, sz = 223, space = 32, placeholder = 95, hyphen = 45, nothing = 0 }; [STAThread] static void Main(string[] args) { for (int char1 = (int) Chars.nothing; char1 <= (int) Chars.sz; char1++) { // ... } } }