object + variable vom Typ Type = typisierte Variable?
-
Hi Leute,
ich habe eine Klasse:
class Item { public Type type; public object data; }
Die beiden will ich jetzt zu einer "normalen" Variable verschmelzen.
Beispiel:
wenn item.type==typeof(string) dann soll
MyMagicFunction(item.type, item.data) einen string zurueckliefern.Siehe auch:
http://www.c-plusplus.net/forum/viewtopic-var-t-is-145395.htmlIrgendwelche Ideen?
-
Mhh. Hab ich dich richtig verstanden, dass der Rückgabetyp abängig vom Typ eines Parameters ist?
Als erste Lösung wär mir jetzt die Verwendung von Generics eingefallen (funktioniert meines erachtens erst ab .net2.0)public T MyMagicFunction<T>(T var1, object data) { return (T)data; }
Nagel mich auf der Syntax nicht fest, ich hab selber noch nicht mit Generics programmiert.
Falls du absolut keine Ahnung hast, von welchem Typ deine Variable ist, dann bleibt allerdings immernoch dem Anwender deiner Funktion die Unterscheidung. Soweit ich weiß gibt es aber eine Möglichkeit den Typ einer Variablen in einer Variablen zu speichern. Ich glaub ich habs in "Modern C++ Design" mal gelesen? Is schon Ewigkeiten her. Vielleicht bietet C# ja diese Möglichkeit. *nachschlag*Hab grad noch was gefunden (C# 2.0 Language Specification). Ob das dein Problem löst, kann ich nicht sagen, da ich nicht genau weiß, was du vor hast. (So fällt übrigens auch die Type Variable weg).
20.6.4 Inference of type arguments
When a generic method is called without specifying type arguments, a type inference process attempts to infer type arguments for the call. The presence of type inference allows a more convenient syntax to be used for calling a generic method, and allows the programmer to avoid specifying redundant type information. For example, given the method declaration:class Chooser { static Random rand = new Random(); public static T Choose<T>(T first, T second) { return (rand.Next(2) == 0)? first: second; } }
it is possible to invoke the Choose method without explicitly specifying a type argument:
int i = Chooser.Choose(5, 213); // Calls Choose<int> string s = Chooser.Choose("foo", "bar"); // Calls Choose<string>
Through type inference, the type arguments int and string are determined from the arguments to the method.
-
Hi cin,
danke fuer deine Antwort, aber leider hilft mir das alles nichts.
Ich habe es im anderen Thread schon geschrieben, aber nochmal kurz zusammengefasst geht es darum:
Ich bau ein Framework, das man ueber eine XML-Datei steuern kann. Unter anderem bietet dieses Framework die Moeglichkeit zwei "Dinge" miteinander zu vergleichen.
Der Anwender legt in der XML-Datei fest von welchem Typ dieses Ding ist. string, int, als Pfad zu interpretieren...
Und genau das will ich erreichen. Generics helfen nciht weiter, weil ich da auch eine klasse angeben muss (also beispielsweise "int") und keinen typ (also beispielsweise typeof(int))Und dein Chooser... Genau das will ich erreichen
Allerdings habe ich eben fuer diesen Zweck noch keine streng-typisierten Variablen.
Schau mal in den anderen Thread rein, falls es noch nciht klar ist.
-
dEUs schrieb:
wenn item.type==typeof(string) dann soll
MyMagicFunction(item.type, item.data) einen string zurueckliefern.Also data ist dann schon immer vom richtigen Typ, oder?
class Item { public void SetData<T>(T data) { this.data = data; this.type = typeof(T); } public T GetData<T>() { return (T)data; } public Type ContainedType {get{ return type; }} private Type type; private object data; }
Jetzt kann man geil holen mit:
Path path = myItem.GetData<Path>();
Ich verstehe dich im anderen Thread jetzt mal so, dass item.GetType() (methode von object) immer == item.Type ist.
Also fliegt das type mal raus.class Item { public void SetData(object data) { this.data = data; } public T GetData<T>() { return (T)data; } public Type ContainedType {get{ return data.GetType(); }} private object data; }
So kann man von außen immer erst fragen was es ist und dann bequem holen. Wenn es nicht das ist, was du willst, dann kannst du auch die ganze Klasse generisch machen und hast compile-time Sicherheit auf Kosten der Flexibilität. Wenn es das auch nicht ist, finde ich es wirklich völlig unverständlich. Für mich sieht das ein bisschen so aus, als versuchtest du, den "Variant"-Typ von Visual Basic nachzubauen. Der ist aber scheiße.
-
Unter anderem bietet dieses Framework die Moeglichkeit zwei "Dinge" miteinander zu vergleichen.
Aber nur zwei Dinge vom gleichen Typ, oder? return a.Equals(b) reicht doch dann.
-
Hm...
Ich bin wohl ne richtige Niete, was das Beschreiben von Problemen angeht
Noch ein Versuch:public class Parameter { private string name; public string Name { get { return name; } } private string data; public string Data { get { return data; } } public void Load(string xmldata) { XmlDocument doc = new XmlDocument(); doc.LoadXml(xmldata); XmlNode root = doc.DocumentElement; name = root.Attributes["name"].Value; data = root.InnerXml; } public object getData() { int i; if(int.TryParse(Data, out i)) return i; else return Data; } } void test(int i) { MessageBox.Show(i.ToString()); } void test(string str) { MessageBox.Show(str); } void function() { Parameter p1 = new Parameter(); p1.Load("<parameter name=\"First\">1</parameter>"); test(p1.getData()); Parameter p2 = new Parameter(); p2.Load("<parameter name=\"First\">somestring</parameter>"); test(p1.getData()); }
So, test(p1.getData()) sollte die int-Variante aufrufen, test(p2.getData()) die string-Variante.
Der Grund für das alles ist ganz einfach folgender:
Je nach Inhalt des parameter-Tags müssen seine Daten anders interpretiert werden. Und genau diese Logik hat in der Klasse Parameter zu sein und nciht ausserhalb. Das ist eigentlich alles, was ich willWenn ich p1.getData().GetType() mache, dann bekomme ich jedesmal sogar den richtigen Typ angezeigt! Die Information ist sogar in dem object-Objekt noch enthalten. Das muss doch dann irgendwie gehen, diese Daten implizit zu konvertieren, oder nciht?
-
Hilft dir das weiter?
if (item.type == typeof(string)) data.ToString(); else if (item.type == typeof(int)) Convert.ToInt32(data); else if (item.type == typeof(char)) Convert.ToChar(data); // usw.
-
Nein.
-
Deine Methode getData() liefert doch etwas vom Typ >Object< zurück.
Mit Object kann man die Datentypen (Werttypen) "neutral" speichern und übergeben. Wenn ich ein int definiere und es zu Object caste, mache ich ein boxing (also packe int in eine box rein, die vom Typ Object ist). Wenn ich mit object arbeiten will, muß ich die Box wieder aufmachen und zum ursprünglichen Datentyp zurückcasten, was man unboxing nennt (sage also, daß >Object< etwas enthält, das ein int sein soll).
Wenn ich wissen will, was >Object< enthält, kann man in C# "is" benutzen.Kuck Dir doch mal in der MSDN mit Filter C# den Inhalt zu "Boxing-Konvertierung (C#)" an. Das ist im Grunde das, was Du willst. Du wirst aber um das casten (boxing/unboxing) nicht herumkommen. Der ganze Spaß kostet natürlich performance, was aber natürlich nicht dramatisch ist, wenn man das sparsam anwendet.
Soweit ich weiß, kann man in C# (ich nutze VB.net, weil mir das besser gefällt) bei überladenden Funktionen lediglich die Parameter anpassen, nicht jedoch den Rückgabewert. Deshalb schwächelt Deine Idee daran, daß Du immer was vom Typ "Object" als allgemeingültiges zurückgeben mußt und der Empfänger halt mit "is" bzw. "typeof" kucken muß, was er da feines gekriegt hat. Macht auch irgendwie Sinn: einen String behandelt man ja i.d.R. anders als ein Integer, weil man mit dem einen Zeichenfolgen speichert und mit dem anderen rechnet.
Ansonsten kann ich nur cin zustimmen, wobei ich mich mit dem Thema "generische Funktion" nicht auskenne (ich vermute, daß ist das gleich wie bei C++ und den Templates)... Das ist aber der nächste logische Schritt: im Object steht ja drin, um was es sich handelt. Damit ist es ja auch denkbar, daß der Compiler automatisch Code zur Verfügung stellt, der von sich aus die richtige Methode aufruft.
Ansonsten sehe ich nur den Weg, um es einfacher zu machen:
void Test(object Obj) { if (Obj == tpyeof(int)){ Test((int)Obj); } else if(Obj == typeof(string)){ Test((string)Obj); }.... }
Damit "kapselst" Du in gewisser Weise die Entscheidung weg, was wie gerufen werden muß. Wenn Du's richtig kapseln willst, mußt Du's halt mit einer Klasse machen, die nur public Test(Obj) kennt und dann intern die richtige "Detail"-Methoden implementiert (also int, string, long etc.). Das wäre dann auch die elegante Methode, die Dir vorschwebt.
-
PC-User schrieb:
Ansonsten sehe ich nur den Weg, um es einfacher zu machen:
void Test(object Obj) { if (Obj == tpyeof(int)){ Test((int)Obj); } else if(Obj == typeof(string)){ Test((string)Obj); }.... }
Damit "kapselst" Du in gewisser Weise die Entscheidung weg, was wie gerufen werden muß. Wenn Du's richtig kapseln willst, mußt Du's halt mit einer Klasse machen, die nur public Test(Obj) kennt und dann intern die richtige "Detail"-Methoden implementiert (also int, string, long etc.). Das wäre dann auch die elegante Methode, die Dir vorschwebt.
Das gefällt mir, danke!
Ach ja... Ich glaube echt, dass das was ich machen will garnicht funktionieren KANN.
Angenommen, ich habe eine Funktion überladen wie oben (einmal mit int-Parametern, einmal mit string-Parametern), meine getData-Funktion liefert aber was vom Typ List zurück, dann haben wir das Problem, dass zur Laufzeit erst festgestellt werden kann, dass es für diesen Aufruf ja garkeine Funktion gibt (wir legen ja erst zur Laufzeit den Rückgabewert fest)Und das geht glaub echt nicht