| 

.NET C# Java Javascript Exception

7
Ich übergebe an eine Prozedur per Parameter Objekte unterschiedlichen Typs, die je nach Typ innerhalb der Prozedur unterschiedlich verarbeitet werden sollen. Der Übergabeparameter hat dementsprechend den Datenyp object. Mit typeof (C#) beziehungsweise TypeOf (VB) nehme ich die Typüberprüfung vor. Wie bekomme ich jetzt aber Zugriff auf die objektspezifischen Eigenschaften und Methoden?
News:
27.10.2011
OopBeginner 51 3
1
Hallo OopBeginner, willkommen bei codekicker, und Glückwunsch, dass gleich Deine erste Frage soviel Interesse hervorgerufen hat! Du hast dafür schon recht viele Bewertungen bekommen. Sollten die Antworten für Dich hilfreich gewesen sein, würden sich deren Autoren umgekehrt sicher auch über Bewertungen von Deiner Seite freuen. Laut Deinem Profil hast Du noch keine vergeben.
Matthias Hlawatsch 28.10.2011
+1 für den Kommentar. Ein Hinweis an prominenter Stelle für diese Regelung würde sicher auch nicht schaden. Anderswo gibt es sogar etwas wie eine "Acceptance Rate"...
puls200 28.10.2011
4 Antworten
3
Die Typumwandlung in VB.NET hat SensenMannLE schon vorgestellt, in C# sähe das so aus:

SpecialType typedObject = (SpecialType)untypedObject;
typedObject.MethodInSpecialType();
//oder kurz
((SpecialType)untypedObject).MethodInSpecialType();

Für Referenztypen hast Du in C# als Alternative noch den as-Operator, der sich insbesondere dann anbietet, wenn für deinen Context die Fälle "ist null" und "ist nicht vom passenden Typ" auf dasselbe hinauslaufen. Du sparst Dir dann den expliziten typeof-Aufruf.

SpecialType typedObject = untypedObject as SpecialType;
if (typedObject != null)
typedObject.MethodInSpecialType();

Wenn Du aber die zu unterstützenden Typen alle unter ein Interface oder gemeinsame Basisklasse bringen kannst, empfehle ich den Ansatz von Jürgen.

Als weitere Alternative könntest Du noch überlegen, ob Du Deine Methode nicht überladen kannst, also statt DoSomething(object arg) mehrere Methoden anbietest: DoSomething(SpecialType1 arg), DoSomething(SpecialType2 arg) usw. Voraussetzung dafür wäre, dass an den aufrufenden Stellen die zu übergebenden Parameter mit dem jeweils passenden Typ deklariert sind (oder notfalls schon dort gecastet werden können), also der Aufrufer nicht auch schon nur ein object in der Hand hat - sonst kann der Compiler nicht die passende Methode aussuchen.
27.10.2011
Matthias Hlawatsch 13,2k 4 9
Der Antwort stimme ich zu, wenn es die Gegebenheiten zulassen/erforderlich machen.
Wenn ich Objekte habe die sich nur durch primitive Parameter unterscheiden, verwende ich mittlerweile oft eine Liste um die Parameter zu halten. Somit können die ganzen Parameter dynamisch über eine Datenbank gesteuert werden und ich benötige nur einen allgemeinen Objekttyp.
SensenMannLE 27.10.2011
"Objekte habe die sich nur durch primitive Parameter unterscheiden" - kannst Du das näher erläutern?
Matthias Hlawatsch 27.10.2011
Ich versuchs mal :). Ich habe im "echten Leben" z.B. zwei Typen von Geräten (Wasserzähler und Heizkostenverteiler). Ich muss mit den Geräten in der Software nichts weiter machen, als die Daten dazu zu halten, damit diese suchbar/editierbar sind. Jetzt nehmen wir mal an der Wasserzähler hat ein Datum "nächste technische Prüfung" und der HKV hat ein Kennzeichen Funk ja/nein. In diesem Fall habe ich nur ein programmtechnisches Objekt (z.B. ein Objekt "Gerät"), welches einfach eine Auflistung hat wo die Parameter gespeichert werden.
SensenMannLE 27.10.2011
Welche Parameter das jeweilige Gerät hat/haben muss ergibt sich aus einer Definition, die ebenfalls in der Datenbank vorhanden ist.
SensenMannLE 27.10.2011
1
Ok, ich glaub ich hab's verstanden. Mit Blick auf das Pseudonym des Fragestellers sollten wir vielleicht den Hinweis ergänzen, dass eine solche Lösung eher unter "pragmatisch" als "OOP" fällt, oder?
Nach der "reinen OO-Lehre" hätte man wohl eher eine Basisklasse Gerät, davon abgeleitet Wasserzähler und HKV, und einen OR-Mapper, der diese Hierarchie auf DB-Tabellen mappt. Wenn es im Code nichts spezielles für WZ und HKV zu tun gibt, kann man dann ja immer allgemein "Gerät" verwenden. - Aber so langsam wird es off-topic, fürchte ich.
Matthias Hlawatsch 27.10.2011
2
Ich würde das folgendermaßen machen:
Das Beispiel ist eigentlich selbsterklärend. Entscheidend ist die Methode "DoSomething". Bei Rückfragen, schreibe einfach einen Kommentar zu meiner Antwort.
Zum Testen kannst du eine C#-Konsolenanwendung erstellen.

public abstract class MyBaseClass
{
public abstract void Foo1();
public abstract void Foo2();
}

public class MyClass1 : MyBaseClass
{
#region Overrides of MyBaseClass

public override void Foo1()
{
Console.WriteLine("MyClass1.Foo1");
}

public override void Foo2()
{
Console.WriteLine("MyClass1.Foo2");
}

#endregion
}

public class MyClass2 : MyBaseClass
{
#region Overrides of MyBaseClass

public override void Foo1()
{
Console.WriteLine("MyClass2.Foo1");
}

public override void Foo2()
{
Console.WriteLine("MyClass2.Foo2");
}

#endregion
}

public class MainClass
{
public void Start()
{
MyClass1 myClass1=new MyClass1();
MyClass2 myClass2=new MyClass2();

DoSomething(myClass1);
DoSomething(myClass2);

Console.ReadLine();
}


private void DoSomething<T>(T myClass) where T : MyBaseClass
{
myClass.Foo1();
myClass.Foo2();
}
}


Nachschlag:
Siehe auch Generic Methods: Methoden und Constraints
27.10.2011
Jürgen Luhr 7,1k 2 9
1
Das ist vom Ansatz her sicherlich das Mittel der Wahl, wenn sich alle zu verarbeitenden Typen unter einer gemeinsamen Basisklasse oder wenigstens einem Interface vereinen lassen. So etwas wie die Datasource-Property in Windows Forms, die auch nur vom Typ object ist, aber je nach tatsächlich übergebenem Typ das passende tut, wird sich so nicht abbilden lassen.
Ansonsten: vielleicht bin ich noch nicht ganz ausgeschlafen, aber warum Du Generics benutzt statt einfach DoSomething(MyBaseClass myClass) zu schreiben, erschließt sich mir aus dem Beispiel gerade nicht.
Matthias Hlawatsch 27.10.2011
@Matthias
Zum ersten Punkt:
Bei einem Parameter von Typ "object" muss innerhalb "DoSomething" der Typ bekannt sein, um eine Methode des Objekts ausführen zu können. Das Resultat wäre eine if..else - Kette mit typeof()-Prüfungen, da OopBeginner unterschiedliche Typen in DoSomething reinreichen möchte. Da vier seiner tags das Wort "objekt" beinhalten wollte ich eine OPP-Antwort geben und if...else mit typeof() vermeiden.

Zum zweiten Punkt:
Da hast du vollkomen recht. In meinem schnell runtergetippten Beispiel wären Generics nicht nötig, zeigt OopBeginner aber, was damit möglich ist.
Jürgen Luhr 27.10.2011
2
Die Abfrage des Types und anschließende Typumwandlung würde ich definitiv vermeiden.

Besser ist es, mehrere überladene DoSomething-Methoden bereitszustellen, die jeweils einen anderen Typen als Übergabeparameter erhalten. Das ist sauber und leicht erweiterbar.
27.10.2011
Andreas Richter 1,7k 1 2 8
Dem kann ich nur zustimmen. Es macht den Code wesentlich leserlicher. Außerdem trennst du dadurch das Verhalten mit den einzelnen Objekttypen. Gruß Andy
cruX 27.10.2011
1
Hallo,

das bekommst Du mit einer Typumwandlung hin. Für VB.NET sieht das wie folgt aus:

CType(meinObjekt, meinObjektTyp).DerParameter
27.10.2011
SensenMannLE 1,2k 2 9

Stelle deine Datentypen-Frage jetzt!