Laden...

Deklaration von Objekt innerhalb von Case

Erstellt von 6274011253792 vor 5 Jahren Letzter Beitrag vor 5 Jahren 1.999 Views
6
6274011253792 Themenstarter:in
7 Beiträge seit 2018
vor 5 Jahren
Deklaration von Objekt innerhalb von Case

Hallo zusammen...

ich hab da ein Anfänger-Deklarationsproblem:

ich möchte ein Objekt einer bestimmten Klasse erstellen, wobei die Klasse abhängig von einem Parameter ist, welchen ich in irgendeiner Weise abfragen muss...

Konkret geht es um eine Outlook Nachrichtenklasse - ist aber IMHO auf jede andere Klasse / Objekttype zu übertragen. Problem ist hier, das ich 137 unterschiedliche Klassen behandeln muss... das bedeutet im Moment, das ich diesen Codeblock hier 137 mal brauche:

switch(MessageClass)
{
   case "IPM.DOCUMENT":
     for (int retrytimes = 1;retrytimes <= 5;retrytimes++)
     {
        try
        {
           var Item = app.Session.OpenSharedItem(@TempFile) as Microsoft.Office.Interop.Outlook.DocumentItem;
           Item.Save();
           if (LogLevel > 1)
           {
              System.IO.File.AppendAllText(MSGLogfile, lt("Message created"));
           }
           Item.Move(objfolder);
           if (LogLevel > 1)
           {
              System.IO.File.AppendAllText(MSGLogfile, lt("Message stored in Folder"));
           }
           RestoreResult = 1;
           break;
        }
        catch (System.Exception ex)
        {
           System.IO.File.AppendAllText(logFileName, lt("Fehler: " + ex.Message));
        }
     }
     break;
[...weitere case's]
}

Statt dessen würde ich lieber sowas in der Art haben - die restliche Verarbeitung halt nur einmal unterhalb des Switch Blocks:

var Item = null;
switch(MessageClass)
{
   case "IPM.DOCUMENT.ACROEXCH.DOCUMENT": Item=app.Session.OpenSharedItem(@TempFile) as Microsoft.Office.Interop.Outlook.DocumentItem; break;
   [...weitere case's]
}
for (int retrytimes = 1;retrytimes <= 5;retrytimes++)
{
   try
   {
      var Item = app.Session.OpenSharedItem(@TempFile) as Microsoft.Office.Interop.Outlook.DocumentItem;
      Item.Save();
      if (LogLevel > 1)
      {
         System.IO.File.AppendAllText(MSGLogfile, lt("Message created"));
      }
      Item.Move(objfolder);
      if (LogLevel > 1)
      {
         System.IO.File.AppendAllText(MSGLogfile, lt("Message stored in Folder"));
      }
      RestoreResult = 1;
   }
   catch (System.Exception ex)
   {
      System.IO.File.AppendAllText(logFileName, lt("Fehler: " + ex.Message));
   }
}

Aber das geht in der Art nicht, weil wenn Item nicht dediziert als app.Session.OpenSharedItem(@TempFile) as Microsoft.Office.Interop.Outlook.DocumentItem declariert ist, funktionier Item.Save() und Item.Move() entsprechend nicht mehr

So dass ich also oben einfach ein Konstrukt habe, das mir die 137 möglichkeiten durchgeht und ein entsprechendes Objekt vom richtigen Typen ausspuckt und ich die restliche verarbeitung dann einfach unten mache (alle anderen Schritte sind ja vollkommen identisch...)

Vermutlich total einfach, aber ich hab da irgendwie das Thema mit den deklarationen und Typen noch nicht so ganz verstanden... und mir fallen auch keine suchbegriffe mehr ein, die ich noch zu Dr. Google schicken könnte 😦 Also sorry, wenn ich euch mit so einem Anfängerquatsch komme...

Vielen Dank
Liebe Grüße

2.079 Beiträge seit 2012
vor 5 Jahren

Verstehe ich das richtig, dass die beiden Methoden Save und Move nur funktionieren, wenn die Variablen den tatsächlichen Typ des Objektes haben? Du darfst also nicht die Basis-Klasse verwenden als Variablen-Typ?
Klingt für mich nach einem groben OOP-Verbrechen ...

Wenn es so ist, wie ich denke, wirst Du nicht ohne Reflection weiter kommen:

class Base
{
    public void DoSomething() => Console.WriteLine("Base");
}
class Child1 : Base
{
    public new void DoSomething() => Console.WriteLine("Child 1");
}
class Child2 : Base
{
    public new void DoSomething() => Console.WriteLine("Child 2");
}
class Program
{
    static void Main(string[] args)
    {
        Base child1 = new Child1();
        Base child2 = new Child2();

        child1.DoSomething(); // Base
        child2.DoSomething(); // Base

        DoSomething(child1); // Child 1
        DoSomething(child2); // Child 1

        Console.ReadKey();
    }

    static void DoSomething(Base item)
    {
        var method = item
            .GetType()
            .GetMethod(nameof(item.DoSomething));

        method.Invoke(item, null);
    }
}

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

6
6274011253792 Themenstarter:in
7 Beiträge seit 2018
vor 5 Jahren

Hallo Palladin,

danke für Deine Antwort.

wenn ich das hier so mache

object Item;
                                        switch ((string)dbReader[1].ToString().ToUpper())
                                        {
                                            case "IPM.DOCUMENT":
                                                Item = app.Session.OpenSharedItem(@TempFile) as Microsoft.Office.Interop.Outlook.DocumentItem;
                                                break;
                                            case "IPM.DOCUMENT.ACROEXCH.DOCUMENT":
                                                Item = app.Session.OpenSharedItem(@TempFile) as Microsoft.Office.Interop.Outlook.DocumentItem;
                                                break;
                                        }
                                        Item.Save();

erhalte ich im Save bereich die folgende Fehlermeldung:

"object" enthält keine Definition für "Save", und es konnte keine Save-Erweiterungsmethode gefunden werden, die ein erstes Argument vom Typ "object" akzeptiert (möglicherweise fehlt eine using-Direktive oder ein Assemblyverweis).

Mit Deinem Beispiel komme ich offen gestanden nicht ganz zurecht... da muss ich nochmal bissern nach Reflection googlen 😃 Soweit bin ich noch nicht... Aber vielen Dank schon mal

2.079 Beiträge seit 2012
vor 5 Jahren

Die Variable ist vom Typ object, das ändert die Situation natürlich.

Lies dir die Fehlermeldung mal genau durch und schau dir lieber die Grundlagen an, anstatt nach Reflection zu suchen. Hilfreich ist auch dieses Buch, da wird das auch behandelt.

Das Problem kurz gefasst:
Der Compiler sucht die Methoden anhand des Typs der Variablen. Der Typ object hat einfach keine Save-Methode und da er nicht weiß, was irgendwann für ein Objekt in dieser Variable "stecken" könnte, kann er auch nicht wissen, dass es irgendwann eine Save-Methode geben wird.

Zu deinem switch:
Für mich sehen die Inhalte in den Cases alle gleich aus? Also warum ein Switch?
Und Du verwendest immer den Typ DocumentItem. Ist das immer dieser Typ? Dann kannst Du diesen Typ auch für die Variable verwenden, wenn nicht, musst Du schauen, ob eine Basis-Klasse oder ein Interface diese Save-Methode hat.

Wenn gar nichts hilft, tut's auch ene Generic-Lösung:

T Save<T>(T item, Action<T> save)
{
    // ...
}

Item = Save(GetItem(), x => x.Save());

Wo ich das schreibe: Bei dem Problem, was ich zuerst vermutet habe, würde das auch helfen, da braucht's doch kein Reflection.

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

6
6274011253792 Themenstarter:in
7 Beiträge seit 2018
vor 5 Jahren

Hallo Palladin,

das Object habe ich oben halt genommen, weil ich da ja noch nicht weiß, was es für ein Objekt wird.

das mit den identischen Cases war ein Copy&Paste fehler…

es sind natürlich unterschiedliche Typen - allerdings immer untertypen von Microsoft.Office.Interop.Outlook… also einmal ist es Noteobject, dann wieder Postobject oder einfach nur Mailitem…

Alle diese Typen haben .Save und .Move

Vielen Dank! Du hast mich da auf eine klasse Idee gebracht... ich mache einfach eine Funktion und übergebe aus der Case Anweisung das Objekt vom richtigen Typ...

Probier ich gleich mal

Danke Dir!
Liebe Grüße

2.079 Beiträge seit 2012
vor 5 Jahren

Wenn die Typen keine Basis haben, die die zwei Methoden definiert, reicht es nicht, das Objekt zu übergeben.
Du musst die zwei Methoden als Parameter an die Methode übergeben. Stichwort: Delegaten

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

6
6274011253792 Themenstarter:in
7 Beiträge seit 2018
vor 5 Jahren

Müsste das nicht funktionieren:


void Funktion(Parameter)
{
   Parameter.Save()
   Parameter.Move()
}

Main
{
switch(MESSAGECLASS)
case "IPM.POST":
   var ITEM= Microsoft.Office.Interop.Outlook.PostItem;
   Funktion(ITEM);
   Break;
case "IPM.NOTE":
   var ITEM= Microsoft.Office.Interop.Outlook.NoteItem;
   Funktion(ITEM);
   Break;
}


2.079 Beiträge seit 2012
vor 5 Jahren

Wie gesagt: Stichwort Delegaten 😛
Hilfreich könnte auch das Stichwort "Lambda" sein.

Mein letzter Beispiel-Code von eben arbeitet so. Leicht angepasst:

void Save<T>(T item, Action<T> save)
{
    save(item);
}

Save(Item, x => x.Save());

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

6
6274011253792 Themenstarter:in
7 Beiträge seit 2018
vor 5 Jahren

OK. Ich les mich da mal ein...

vielen herzlichen Dank!

Liebe Grüße und schönen Abend

4.939 Beiträge seit 2008
vor 5 Jahren

Hallo,

besonders für COM wurde in C# das Schlüssewort dynamic eingeführt, s.a. Verwenden des Typs dynamic.
Deklariere also einfach


dynamic item;

und du kannst dann den Code aus deinem 2. Beitrag nutzen. 😉
Falls die Methoden jedoch dann nicht existieren, erhältst du zur Laufzeit entsprechende Exceptions.