frage zu arrays
-
hi!
char[] array1 = {'h','a','l','l','o'}; string[] str1 = {"string1"}; oder doch: string[] str1 = new string[] {"string1"}; warum funktioniert sowas: string[] str1 = new string[2] {"string1", "hallo"};
wie kann man das char array einfacher initialisieren? nimmt man die string initialisierung mit new lieber?
cu
-
am Anfang kannst du es ohne new initialisieren und zur Laufzeit wenn die Größe noch nicht feststeht nimmste new.
-
class Circle { public void PrintArray(object[] arr1, object[] str1) { foreach (object temp in arr1) Console.WriteLine("Word: {0}", temp); foreach(object temp1 in str1) Console.WriteLine("Word: {0}", temp1); } } class Test { public static void Main() { Circle c = new Circle(); char[] array1 = {'h','a'}; string s = "I will not buy this record, it is scratched."; char[] separators = {' '}; string[] str1 = s.Split(separators); c.PrintArray(((object[])(array1)), str1); Console.Read(); } } error CS0030: Cannot convert type 'char[]' to 'object[]'
was mach ich da falsch? ist char nicht von object abgeleitet? warum funktioniert der cast hier nicht? und warum brauch ich für string keinen cast?
cu
-
char ist ein ValueType und Object ist ein ReferenceType. Es ist zwar angeblich von Objekt abgeleitet, aber richtiger wäre es zu sagen, dass es die Schnittstelle von Object implementiert.
Du kannst ein char[] nicht in ein Object[] casten, denn der Elementtyp eines Object[] ist die Referenz. Deshalb kannst du ein class Foo[] in Object[] casten, denn der Elementtyp ändert sich nicht. Es ist immer noch eine Referenz.
Bei char[] geht das nicht, denn da ist der Elementtyp char, ohne dass man dies ändern kann.Du kannst höchstens ein Object[] verwenden und chars in Objects boxen:
object[] foo = new object[10]; foo[0] = 'f';
-
hi leute!
hab mal in mein buch nachgelesen:
Ausnahmslos alle Klassen lassen sich auf einen gemeinsamen Typ zurückführen, weil sie grundsätzlich alle von ihm abgeleitet sind: Es ist der Typ System.Object. Jede .NET Klasse wird aus dieser abgeleitet, auch wenn dies nicht explizit angegeben ist...System.Object ist also eine Basisklasse aller .NET Klassen...objekt ist also nur eine klassse, die alle grundlegenden eigenschaften implemntiert...
die wirkliche idee von object ist, dass damit jedes objekt einen hashcode hat?
Möglicherweise ist der Typ einer Objectvar. zur Entwicklungszeit noch nicht bekannt und kann erst zur Laufzeit bestimmt werden. Um dies zu ermöglichen, können Sie eine Objectvar. vom Start vom Typ System.Object deklarieren...
char ist also ein valuetyp (und erbt nicht von der Basisklasse System.Object???) und object ein referencetype...was heisst das? was ist dann string?
cu
-
char ist ein struct und string ist eine klasse. Instanzen von Klassen haben Referenzsemantik, d.h. eine Zuweisung kopiert die Referenz auf das Objekt. Bei structs wird der Wert kopiert, also das eigentliche Objekt.
Werttypen (structs) sind eigentlich nicht wirklich von Object abgeleitet, dies wird aber vorgegaukelt, indem man sie als Objekte "boxen" kann.
Das vorgaukeln hat seine Grenzen, bei Arrays sieht man das schon.Normalerweise hast du ein Array, welches so aussieht:
[Object][Object][Object] ... [Object]
Auch wenn das Array einen anderen Elementtyp hat, so lange es Klassen sind, ist es intern nur ein Array von Referenzen. Deshalb kannst du auch die Array-Referenz casten, denn es ist völlig egal, was für Objekte das jetzt wirklich sind.
Bei Werttypen wäre das zu ineffizient, weil dann jedes Objekt erst geboxt werden müsste. Deshalb hat das Array die Form
[char][char][char] ... [char]
Wenn du das in ein Object[] casten willst, geht das schief, weil es hier nicht egal ist. Du hast hier keine Indirektion über Referenzen und du kannst nicht einfach die 2 Bytes von jedem char als Referenz auf ein Objekt interpretieren (die Objekte gibt es ja auch gar nicht).
-
Das ein ValueType[] nicht in ein object[] gecastet werden
kann, steht sogar im C# Standard, vielleicht wirklich aus
Performancegründen. (C# Language Specification 12.5)Werttypen (structs) sind eigentlich nicht wirklich von Object abgeleitet, dies wird aber vorgegaukelt, indem man sie als Objekte "boxen" kann.
Das vorgaukeln hat seine Grenzen, bei Arrays sieht man das schon.Nur weil das in Java so ist, heißt das nicht, dass es
bei .NET genauso sein muss.C# erlaubt eine Konvertierung von int[] zu object[] zwar nicht, die CLR aber
sehr wohl. Dazu müsstest aber entweder wirklich IL coden oder mit System.Reflection.Emit arbeiten.grüße
Hab vergessen zu sagen:
public static void F(int[] arr) { object[] objArr = new object[arr.Length]; arr.CopyTo(objArr, 0); // ... }
Ist im Prinzip das selbe wie Optimizer vorgeschlagen hat ..
-
Tankian schrieb:
Nur weil das in Java so ist, heißt das nicht, dass es
bei .NET genauso sein muss.Höh? Bei Java sind die Werttypen primitiv, die sind ganz sicher schon mal nicht von Object abgeleitet.
Bei .Net sind structs vom Konzept her von Object abgeleitet, aber Aufrufe der Methoden von System.Object resultieren in Boxing. Eigentlich sind sie also gar nicht abgeleitet, sondern werden nur bei Bedarf geboxt. Es gibt keine direkte Vererbung bei value types, kann es auch nicht geben. Sie haben keine vtable, keine Reflection-Informationen, gar nichts.Tankian schrieb:
C# erlaubt eine Konvertierung von int[] zu object[] zwar nicht, die CLR aber
sehr wohl.Nein. Du kannst das nicht konvertieren. Bei classes ist das Array-Element eine Referenz, bei structs nicht. Du kannst nicht einfach die 4 bytes eines ints nehmen und als Referenz interpretieren. Die einzig mögliche Konvertierung ist, ein neues Array Object[] zu erstellen und alle Werte zu boxen.
-
Du kannst zwar ein char-Array nicht nach object[] konvertieren/boxen, aber nach object und zwar der Klasse Array. Deswegen funktioniert folgender Code:
class Circle { public void PrintArray(object arr1, object[] str1) { foreach (object temp in ((Array)arr1) ) Console.WriteLine("Word: {0}", temp); foreach(object temp1 in str1) Console.WriteLine("Word: {0}", temp1); } } class Test { public static void Main() { Circle c = new Circle(); char[] array1 = {'h','a'}; string s = "I will not buy this record, it is scratched."; char[] separators = {' '}; string[] str1 = s.Split(separators); c.PrintArray(((object)(array1)), str1); Console.Read(); } }
Man darf der Funktion PrintArray natürlich nur ein Array übergeben, sonst funktioniert die Konvertierung natürlich nicht. Für String funktioniert es, da es ja direkt von der Klasse object abgeleitet und ein Referenztyp ist.
-
Optimizer schrieb:
Tankian schrieb:
C# erlaubt eine Konvertierung von int[] zu object[] zwar nicht, die CLR aber
sehr wohl.Nein. Du kannst das nicht konvertieren. Bei classes ist das Array-Element eine Referenz, bei structs nicht. Du kannst nicht einfach die 4 bytes eines ints nehmen und als Referenz interpretieren. Die einzig mögliche Konvertierung ist, ein neues Array Object[] zu erstellen und alle Werte zu boxen.
Hast es ausprobiert auch ?
Hier hast den kommentierten IL-Code:.method public instance void Main() cil managed { // Codegröße 50 (0x32) .maxstack 3 // int[] intArr; // object[] objArr; .locals init (int32[] V_0, object[] V_1) // intArr = new int[3]; IL_0000: ldc.i4 0x3 IL_0005: newarr [mscorlib]System.Int32 IL_000a: stloc.0 // intArr[0] = 3; IL_000b: ldloc.0 IL_000c: ldc.i4.0 IL_000d: ldc.i4.3 IL_000e: stelem.i4 // intArr[1] = 5; IL_000f: ldloc.0 IL_0010: ldc.i4.1 IL_0011: ldc.i4.5 IL_0012: stelem.i4 // inArr[2] = 7; IL_0013: ldloc.0 IL_0014: ldc.i4.2 IL_0015: ldc.i4.7 IL_0016: stelem.i4 // objArr = intArr; IL_0017: ldloc.0 IL_0018: stloc.1 // Console.WriteLine((int)objArr[0]); IL_0019: ldloc.1 IL_001a: ldc.i4.0 IL_001b: ldelem.i4 IL_001c: call void [mscorlib]System.Console::WriteLine(int32) // Console.WriteLine((int)objArr[1]); IL_0021: ldloc.1 IL_0022: ldc.i4.1 IL_0023: ldelem.i4 IL_0024: call void [mscorlib]System.Console::WriteLine(int32) // Console.WriteLine((int)objArr[2]); IL_0029: ldloc.1 IL_002a: ldc.i4.2 IL_002b: ldelem.i4 IL_002c: call void [mscorlib]System.Console::WriteLine(int32) // return; IL_0031: ret } // end of method App::Main
Console schrieb:
3
5
7Außerdem steht zum Beispiel in IL-Metadaten eh fast nichts mehr,
was zwischen Reference Type und Value Type unterscheidet.using System; using System.Runtime.InteropServices; struct MyValueType { } [StructLayout(LayoutKind.Sequential, Pack = 0, Size = 1)] sealed class MyReferenceType { }
.class private sequential ansi sealed beforefieldinit MyReferenceType extends [mscorlib]System.Object { .pack 0 .size 1 } // end of class MyReferenceType .class private sequential ansi sealed beforefieldinit MyValueType extends [mscorlib]System.ValueType { .pack 0 .size 1 } // end of class MyValueType
Kann ja trotzdem noch gut möglich sein, dass char, int etc.. wirklich
nicht von object erben. Dann zweifel ich aber generell jede Vererbung an ..grüße
-
Tankian schrieb:
Kann ja trotzdem noch gut möglich sein, dass char, int etc.. wirklich
nicht von object erben.Die Klassenhierarchie kann man doch im Objektbrowser von VS.NET sehen
System.Char | |-IComparable |-IConvertible |-ValueType | |-Object System.String | |-ICloneable |-IConvertible |-IComparable |-IEnumerable |-Object System.Int32 | |-IComparable |-IConvertible |-IFormattable |-ValueType | |-Object System.Array | |-ICloneable |-ICollection | | | |-IEnumerable |-IEnumerable |-IList | |-ICollection | | | |-IEnumerable |-IEnumerable
-
masterofx32 schrieb:
Tankian schrieb:
Kann ja trotzdem noch gut möglich sein, dass char, int etc.. wirklich
nicht von object erben.Die Klassenhierarchie kann man doch im Objektbrowser von VS.NET sehen
Optimizer zweifelt ja an, dass ValueTypes wirklich von object erben. Damit
wollte ich nur sagen, dass es irgendwie in ner versteckten Ecke der CLR
eventuell wirklich der Fall ist, dass ValueTypes nicht von object erben und
das nur vorgetäuscht wird. Falls ja, dann is es so gut getarnt, dass ich eben
alle Vererbungen auf ihre Korrektheit anzweifeln würde.
Jetzt klar, was ich meinte ?
-
Naja, das ist ja vom Prinzip her egal, was in der IL dabei rauskommt. C++ täuscht auch vor, objektorientiert zu sein. Das, was dabei rauskommt (Assembler/Maschinencode), ist es jedenfalls nicht
-
Tankian schrieb:
Optimizer schrieb:
Tankian schrieb:
C# erlaubt eine Konvertierung von int[] zu object[] zwar nicht, die CLR aber
sehr wohl.Nein. Du kannst das nicht konvertieren. Bei classes ist das Array-Element eine Referenz, bei structs nicht. Du kannst nicht einfach die 4 bytes eines ints nehmen und als Referenz interpretieren. Die einzig mögliche Konvertierung ist, ein neues Array Object[] zu erstellen und alle Werte zu boxen.
Hast es ausprbiert auch ?
Hier hast den kommentierten IL-Code:Was du hier zusammenhackst ist ein typunsicherer "reinterpret_cast". Das ist keine Konvertierung. Wenn du irgendwelche Bytes hast (z.B. ein char[]), dann kannst du es auf die Weise nicht zu einem Object[] machen, weil du dann die chars als Referenzen interpretieren musst und auf was sollen die denn bitte zeigen, wenn du nicht die entsprechenden Objekte allokierst?
Und so ganz nebenbei machst du jetzt auch noch genau das Gegenteil, nämlich du interpretierst du Referenzen als int. Das ist erstens auch typunsicher und zweitens nicht mal das, über was wir gesprochen haben.
Also in diesem Zusammenhang völlig sinnlos, was soll das jetzt werden? Komisch, wenn du schon so gerne low-level rumhackst, wieso ist dir dann das nicht klar, dass ein einfacher cast char[] -> Object[] gar nicht funktionieren kann?
-
Ich verstehe irgendwie die Problematik nicht ganz. Warum sollte man ein char[] in ein object[] konvertieren können? Dass es nicht geht, hat doch nichts mit Referenztypen und Werttypen zu tun, sondern einfach nur damit, dass ein char[] von System.Array erbt und von daher auch nur in ein object zu konvertieren ist. In ein object[] könnte man nur die Arrayelemente konvertieren, aber an die kommt man nicht heran, da sie in der Klasse zu stark eingekapselt sind und von daher nur einzeln mit dem []-Operator bekommen werden können.
-
Optimizer schrieb:
Was du hier zusammenhackst ist ein typunsicherer "reinterpret_cast". Das ist keine Konvertierung. Wenn du irgendwelche Bytes hast (z.B. ein char[]), dann kannst du es auf die Weise nicht zu einem Object[] machen, weil du dann die chars als Referenzen interpretieren musst und auf was sollen die denn bitte zeigen, wenn du nicht die entsprechenden Objekte allokierst?
Dann hast aber bis jetzt zu 99% typunsichere Programme erstellt, denn genauso
sieht ein Zuweisung von einem abgeleiteten Typ auf einen Basis-Typ aus ..Wenn es typunsicher wäre, würde es ja wohl ne Exception werfen und schon
gar nicht, das gewünschte Ergebniss liefern. Wie wenn es Zufall wäre, das
es klappt ..[edit]
Das wär ja im Prinzip das selbe wie wenn du sagen würdest, ein Cast
von int32 nach int64 ist typunsicher, da möglicherweise die restlichen
32 Bit undefiniert sind. Wir alle wissen, dass dem nicht der Fall ist,
weil die CLR weiß was zu tun ist. Könnte doch genauso gut sein, dass die
CLR weiß was zu tun ist, wenn ich eben ein Array von Wertetypen einem
Array von objects zuweise.
[/edit]Ich versuch einfach nochmal den Thread hier zusammenzufassen ..
Ein Cast von char[] nach object[] ist in C# nicht erlaubt. Deine Begründung
baute auf die Unterschiede zwischen Referenztypen und Wertetypen auf. Wenn
es allerdings wirklich davon abhängen würde, müsste die CLR bei so nem Cast
ja bereits schreien. Von ihr hängt ja letztendlich ab, was erlaubt ist und
was nicht, was typsicher ist und was nicht, etc .. Mit meinem Beispiel
"dahingehackt" in IL wollte ich aber nur beweisen, dass die CLR eben nicht
aufschreit, sondern nur der C# Compiler. Somit kann der Unterschied zwischen
Referenz- und Wertetyp nicht der Grund sein, warum der Cast nicht erlaubt ist.Hoffentlich konnte ich jetzt meinen Gedankengan verdeutlichen ..
masterofx32 schrieb:
Ich verstehe irgendwie die Problematik nicht ganz. Warum sollte man ein char[] in ein object[] konvertieren können? Dass es nicht geht, hat doch nichts mit Referenztypen und Werttypen zu tun, sondern einfach nur damit, dass ein char[] von System.Array erbt und von daher auch nur in ein object zu konvertieren ist. In ein object[] könnte man nur die Arrayelemente konvertieren, aber an die kommt man nicht heran, da sie in der Klasse zu stark eingekapselt sind und von daher nur einzeln mit dem []-Operator bekommen werden können.
...
string[] strArr = { "Hello", "World" }; object[] objArr = strArr;
-
Hmm, OK, mein Argumentevorrat ist leer. Ich klinke mich dann mal aus der Diskussione aus - tschühüs
-
@Tankian:
Du kapierst es nicht, dass die Repräsentation anders ist. char[] -> object[] ist ein völlig anderer Fall als class Foo[] -> object[]. Wenn du die Referenz von char[] auf object[] ändern könntest, würden die chars als Referenzen interpretiert werden und das geht halt einfach nicht, weil die dann irgendwo ins Nirvana zeigen. Wenn du keine Objekte (also geboxte chars) erstellst, was soll denn dann am Ende rauskommen?
Dass class Foo[] -> Object geht, ist ja sofort einsichtig: Der Elementtyp des Arrays ist immer noch eine Referenz. Das kannst du aber für ein char[] nicht machen, du hast danach nichts mehr, was irgendwie noch brauchbar ist. Und natürlich wirst du dann auch irgendwann deine AccessViolationException kriegen, auf die du schon sehnsüchtig wartest.Was glaubst du denn, hast du mir mit deinem Code gezeigt? Gar nichts. Absolut überhaupt gar nichts. Weil du was völlig anderes gemacht hast, ich kann mir nicht mal einen Grund vorstellen, warum du den überhaupt gebracht hast. Mit dem Thread hatte das jedenfalls nichts zu tun.
Dann hast aber bis jetzt zu 99% typunsichere Programme erstellt, denn genauso
sieht ein Zuweisung von einem abgeleiteten Typ auf einen Basis-Typ aus ..Völliger Unfug. Hier änderst du nur den statischen typ einer Referenz und referenzierst anschließend sogar noch das selbe Objekt. Diesen Cast gibt es nicht mal mehr im CIL Code. Für char[] -> object[] müsstest du etwas, was nicht mal ne Referenz ist, als Referenz interpretieren, was dann auf irgendwas (und was?) zeigt und das Verweisziel gibt es nicht mal. Mir ist nicht einsichtig, warum du da einen Zusammenhang siehst.
Somit kann der Unterschied zwischen
Referenz- und Wertetyp nicht der Grund sein, warum der Cast nicht erlaubt ist.Ja sicher. *kopfschüttel*
Einigen wir uns doch einfach darauf: Du postest hier Code in einer .Net Sprache deiner Wahl, der einfach mal schnell ein char[] in ein Object[] umwandelt, also ohne ein Object[] anzulegen und die einzelnen chars auszulesen und geboxed ins Object[] abzulegen. Und bitte keinen anderen Code mehr...
-
Überleg dir das doch mal anhand von C++ (standard) Code:
Du hast ein char[]. Und das willst du in ein Object*[] casten.Pseudocode:
char a[10]; Object* b[10] = reinterpret_cast<Object*[]>(a);
Was glaubst du, wird das? Das wird undefiniertes Verhalten hoch 10. Das fängt ja schon damit an, dass sizeof(char) nicht unbedingt sizeof(Object*) ist.
-
Optimizer schrieb:
@Tankian:
Du kapierst es nicht, dass die Repräsentation anders ist. char[] -> object[] ist ein völlig anderer Fall als class Foo[] -> object[].Natürlich ist die Represäntation nach aussen hin anders. Aber intern
könnte der CLR doch vllt sogar egal sein ob es ein Wertetyp oder Referenztyp
ist. Vllt ist intern ein Wertetyp sogar nur ein Referenztyp, etc .. Sind zwar
alles Mutmaßungen, aber damit sollte klar werden, dass man eben nicht mit
absolut 100% Sicherheit sagen kann, was die CLR intern alles erledigt.Woher willst du wissen, dass die CLR eine Konvertierung von char[] nach object[]
nicht eh wieder so implementiert wie es bereits vorgeschlagen wurde (Boxen in
einer Schleife). Wenn du mir das zeigen kannst, durch irgendnen MSDN-Artikel,
Beispielcode, etc.. dann ist der Code denn ich gepostet habe wirklich typunsicher.
Ansonsten funktioniert er prima ..Optimizer schrieb:
Was glaubst du denn, hast du mir mit deinem Code gezeigt? Gar nichts. Absolut überhaupt gar nichts. Weil du was völlig anderes gemacht hast, ich kann mir nicht mal einen Grund vorstellen, warum du den überhaupt gebracht hast. Mit dem Thread hatte das jedenfalls nichts zu tun.
Der Ausgangscode in C#:
int[] intArr = { ... }; // ob char oder int is ja egal .. object[] objArr = intArr; // nicht gültig ..
Nun mein IL-Code wieder zurück in C#:
int[] intArr = new int[3]; intArr[0] = 3; intArr[1] = 5; intArr[2] = 7; object[] objArr = intArr; // in IL eben erlaubt .. // unwichtiger Rest ...
Die restlichen Aufrufe von Console.WriteLine() waren ja nur für die Ausgabe
zuständig, damit ich zeigen konnte, dass auch wirklich 3, 5 und 7 in objArr
stehen.Jetzt würde ich aber gerne wissen, inwiefern
mein Code am Thema vorbeiging ..Optimizer schrieb:
Überleg dir das doch mal anhand von C++ (standard) Code:
Du hast ein char[]. Und das willst du in ein Object*[] casten.Pseudocode:
char a[10]; Object* b[10] = reinterpret_cast<Object*[]>(a);
Das sowas undefiniert ist, ist mir klar. Ich versteh auch, dass
eine Zuweisung von einem Wertetyp auf einen Referenztyp ohne
Boxing undefiniert sein müsste. Allerdings wie bereits gesagt,
wird das Boxing bei Arrays vielleicht wieder anders erledigt.
(oder eben noch "automatischer", so das man eben selbst in IL
Code nichts mehr davon sieht ..)Falls immernoch unklar sein sollte, was ich meine, bzw. du
immernoch glaubst ich bin am Thema vorbeigegangen, dann frag
ich dich eben mal:Warum funktioniert mein IL-Code? Erklär mir das bitte, aber
komm erst mit Behauptungen wie typunsicher, etc.. wenn du
dafür auch halbwegs handfeste Beweise hast (eben Artikel, etc..).grüße
-
Tankian schrieb:
Natürlich ist die Represäntation nach aussen hin anders. Aber intern
könnte der CLR doch vllt sogar egal sein ob es ein Wertetyp oder Referenztyp
ist. Vllt ist intern ein Wertetyp sogar nur ein Referenztyp, etc .. Sind zwar
alles Mutmaßungen, aber damit sollte klar werden, dass man eben nicht mit
absolut 100% Sicherheit sagen kann, was die CLR intern alles erledigt.Nein, Value Types sind nicht intern Reference Types.
Woher willst du wissen, dass die CLR eine Konvertierung von char[] nach object[]
nicht eh wieder so implementiert wie es bereits vorgeschlagen wurde (Boxen in
einer Schleife).Du schreibst doch den CIL Code selber. Tust du dort sowas? Nein? Dann ist es auch nicht drin.
Der Ausgangscode in C#:
int[] intArr = { ... }; // ob char oder int is ja egal ..
Die restlichen Aufrufe von Console.WriteLine() waren ja nur für die Ausgabe
zuständig, damit ich zeigen konnte, dass auch wirklich 3, 5 und 7 in objArr
stehen.Jetzt würde ich aber gerne wissen, inwiefern
mein Code am Thema vorbeiging ..Nein. Ob char oder int ist nicht egal, weil sizeof(char) != sizeof(int).
Ja geil. Da stehen wirklich 3, 5 und 7 drin. SUPER! Caste das jetzt bitte in ein Object[] und liefer mir die Objekte, die das Array dann in referenziert.Checkst du's nicht? Oder bist du uneinsichtig? Wie auch immer, für mich ist das hier beendet, ist doch lächerlich. Du gibst ja selber zu, dass der C++ Code undefiniertes Verhalten hätte. Aber wie zum Beweis, dass es in .Net geht zeigst du mir, dass 3, 5 und 7 drin stehen, also dein Object* den Wert 3 und 5 und 7 hat. Das damit referenzierte Objekt, welches es gar nicht gibt, interessiert dich nicht und dass das Array als Object[] völlig nutzlos ist, was ich dir die ganze Zeit sage, interessiert dich auch nicht. Stattdessen zeigst du mir, dass wenn du es nicht änderst immer noch das Bitmuster von 3, 5 und 7 drin ist.
Wenn das alles ist, was du mir zu sagen hast, enttäusche ich dich nur ungern, aber das hätte ich fast auch vermutet.</Diskussion>