Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
"Zeiger" oder Kopie
codester
myCSharp.de - Member



Dabei seit:
Beiträge: 20
Herkunft: Saarland

beantworten | zitieren | melden

Zitat
Ein allgemeines Clone ist schon deshalb schlecht, weil dann auch Singletons geklont werden könnten... was das Singleton ad absurdum führen würde.

KÖNNTE - Niemand muss auch nur irgendwas klonen, aber man hätte die MÖGLICHKEIT
Wir alle sind Untertanen unseres gütigen, weisen und unermesslich reichen Herrschers William Gates des Dritten
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo codester,

ja, aber wer will schon klonen? Das braucht man doch quasi nie. Meistens will man sich den Zustand eines Objekts merken (und bei Bedarf auf wiederherstellen), aber man will doch selten das gleiche Objekt mehr als einmal haben. Darum geht ja auch die ganze Diskussion in Kopie ohne ICloneable : Wie man sich den Zustand eines Objekts merken kann, ohne es zu klonen.

herbivore
private Nachricht | Beiträge des Benutzers
0815Coder
myCSharp.de - Member



Dabei seit:
Beiträge: 770

beantworten | zitieren | melden

Zitat von codester
Zitat
Ein allgemeines Clone ist schon deshalb schlecht, weil dann auch Singletons geklont werden könnten... was das Singleton ad absurdum führen würde.

KÖNNTE - Niemand muss auch nur irgendwas klonen, aber man hätte die MÖGLICHKEIT

Genau. Man hätte die Möglichkeit, weniger robuste Software zu schreiben, genau das passiert, wenn man Singletons klont, das kann nur schiefgehen.

@herbivore: ich glaub jetzt weiss ich worauf du mit "robust" wirklich rauswolltest (Wen's interessiert: IList<T> oder List<T> als Funktionsrückgabewert?)

edit: Name des verlinkten Threads korrigiert... *doof*
loop:
btst #6,$bfe001
bne.s loop
rts
private Nachricht | Beiträge des Benutzers
codester
myCSharp.de - Member



Dabei seit:
Beiträge: 20
Herkunft: Saarland

beantworten | zitieren | melden

Ich versuche mittlerweile seit geraumer Zeit, das ganze mit BusinessObjects zu machen, sieht im Moment auch noch nicht mal schlecht aus, aber es gibt ein Problem:

Man soll der Auflistung (über das Dialogfeld) auch Elemente hinzufügen können (auch entfernen und innerhalb der Auflistung verschieben). Das müsste ich dann auch wieder rückgängig machen können, deshalb meine Frage:

Kann ich von BusinessObject erben und es so um eine Eigenschaft vom Typ List<T> erweitern? (Klar kann ich, aber funktioniert das Rollback dann noch?). Dann könnte ich beim Aufruf von ShowDialog nämlich diese Eigenschaft mit der übergebenen Auflistung belegen. Dann StartTransaction und ein bischen an der Auflistung rumgefummelt, wenns dem user dann doch nicht gefällt sage ich RollBackTransaction und die Auflistung ist wieder in ihrem Urzustand.
Ich habs auch schon probiert aber irgendwie hats nicht hingehauen und jetzt würd ich gern wissen, ob ich da einen Fehler gemacht hab oder ob Businessobject das sowieso nicht kann
Wir alle sind Untertanen unseres gütigen, weisen und unermesslich reichen Herrschers William Gates des Dritten
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo codester,
Zitat
Kann ich von BusinessObject erben und es so um eine Eigenschaft vom Typ List<T> erweitern? (Klar kann ich, aber funktioniert das Rollback dann noch?).
Ja, du müsstest nur _StartTransaction virtuell machen und dann so überschreiben, dass die Liste (flach) kopiert und in _dictFields unter dem Namen ihrer Variablen eingetragen wird.

Ist quasi das gleiche wie in settings verwerfen .

Du könntest sogar BusinessObject (also das originale _StartTransaction) so erweitern, dass es mit Listen (und anderen Collections) grundsätzlich so verfährt. Wäre eine sehr sinnvolle Erweiterung. Wenn du das machst, kannst du gleich gucken, ob in der Collection BusinessObjects enthalten sind und wenn ja, diese in die laufende Transaktion einschließen. Das wäre dann eine erst recht sinnvolle Erweiterung. Wenn du das tust, kannst du einen Code gerne hier posten.

herbivore
private Nachricht | Beiträge des Benutzers
codester
myCSharp.de - Member



Dabei seit:
Beiträge: 20
Herkunft: Saarland

beantworten | zitieren | melden

ok, ich versuchs mal
Wir alle sind Untertanen unseres gütigen, weisen und unermesslich reichen Herrschers William Gates des Dritten
private Nachricht | Beiträge des Benutzers
codester
myCSharp.de - Member



Dabei seit:
Beiträge: 20
Herkunft: Saarland

beantworten | zitieren | melden

Ich hoffe, ich mache das, was du meinst:

         
// Die Schleife ist notwending, weil man sonst nicht an die privaten
      // Felder der Oberklassen kommt.
      for (t = GetType(); t != typeof(BusinessObject); t = t.BaseType)
      {
        afi = t.GetFields(BindingFlags.GetField
                         | BindingFlags.Instance
                         | BindingFlags.NonPublic
                         | BindingFlags.DeclaredOnly
                         | BindingFlags.Public); // nur zur Sicherheit
        foreach (FieldInfo fi in afi)
        {
#if SW_VERBOSE
            Console.WriteLine (new String (' ', 3 * iLevel)
                               + fi.DeclaringType + "." + fi.Name);
#endif
          if (fi.FieldType.IsEnum)//Dieser if-Block ist neu
          { 
          _dictFields[fi]=new List<char>(fi.GetValue(this));//Zu dieser Zeile hab ich zwei fragen (siehe unten)
          }
          else
          {          _dictFields[fi] = fi.GetValue(this);//das hier stand vorher statt dem if-Block
           }

        }
        listfiAll.AddRange(afi);
      }

Zwei Fragen:

1. Wie kann ich das Ergebnis von fi.GetValue(this) in einen Typ konvertieren, den der Kopierkonstruktor akzeptiert?
2. Wie kann ich den richtigen Typparameter übergeben? Den genauen Typparameter der Auflistung zu ermitteln, ist nicht schwer, das geht mit GetGenericArguments, aber das kann ich nicht so einfach in die eckigen Klammern schreiben...
Wir alle sind Untertanen unseres gütigen, weisen und unermesslich reichen Herrschers William Gates des Dritten
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo codester,

die Stelle ist richtig. Die if-Abfrage ist falsch. Du willst ja herausbekommen, ob du einen Listentyp hast, nicht ob du einen enum-Typ hast.

new List<char> ist - wie du ja selbst sagst - ungünstig, weil der Code dann nicht für beliebige Elementtypen funktioniert. Vermutlich ist es besser hier Activator.CreateInstance zu verwenden und damit Punkt 2 zu lösen. Das enthebt dich gleichzeitig der der Notwendigkeit der Typkonvertierung des Arguments und löst damit auch gleich Punkt 2.

herbivore
private Nachricht | Beiträge des Benutzers
codester
myCSharp.de - Member



Dabei seit:
Beiträge: 20
Herkunft: Saarland

beantworten | zitieren | melden

Ich glaube das müsstes jetzt sein, aber bei der if-Anweisung bin ich mir noch nicht ganz sicher:

 
if (fi.FieldType.GetInterface("IEnumerable") != null)
  {
    _dictFields[fi]=Activator.CreateInstance(fi.FieldType,fi.GetValue(this));
  }
else
  {          
    _dictFields[fi] = fi.GetValue(this);
  }

Hab das ganze auch schon getestet (funktioniert!!!), aber um es in mein Dialogfeld einzubauen hab ich im Moment keine Zeit, werds heut nachmittag mal probieren.
Wir alle sind Untertanen unseres gütigen, weisen und unermesslich reichen Herrschers William Gates des Dritten
private Nachricht | Beiträge des Benutzers
codester
myCSharp.de - Member



Dabei seit:
Beiträge: 20
Herkunft: Saarland

beantworten | zitieren | melden

Mit dem code oben gibts ein Problem: Was mach ich mit nicht generischen Auflistungen?

Businessobject müsste ja erst mal zwischen generischen und nicht generischen unterscheiden, der if-Block sieht dann so aus:

 
if (fi.FieldType.GetInterface("IEnumerable") != null)
  {
    if (fi.FieldType.IsGenericType)
      {
        _dictFields[fi]=Activator.CreateInstance(fi.FieldType,fi.GetValue(this));
       }
    else
      {
         //Aber was mach ich hier???
      }
  }
else
  {          
    _dictFields[fi] = fi.GetValue(this);
  }

Wie aber erstelle ich eine flache Kopie einer nicht generischen Auflistung?
Wir alle sind Untertanen unseres gütigen, weisen und unermesslich reichen Herrschers William Gates des Dritten
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo codester,
Zitat
Was mach ich mit nicht generischen Auflistungen?
ich glaube die untypisierten Collections aus System.Collections implementieren alle (oder zumindest teilweise) ICloneable.
Zitat

_dictFields[fi]=Activator.CreateInstance(fi.FieldType,fi.GetValue(this));
Ob diese Anweisung funktioniert hängt davon ab, ob die Collection einen "Copy-Konstruktor" implementiert. Es mag sein, dass bei den meisten oder sogar allen Collections aus System.Collections.Generic der Fall ist, aber man kann es nicht für alle (eigenen/fremden) Collections, die IEnumerable implementieren, voraussetzen. Insofern solltest du das vorher prüfen oder aber die Exception fangen und dann auf das Kopieren verzichten und die normale Zuweisung _dictFields[fi] = fi.GetValue(this); durchführen.

Ich kann das momentan nicht selber testen oder verifizieren, aber du gehst auf jeden Fall in die richtige Richtung.

Schön wäre noch, wenn du den Typ der Elemente prüfen würdest, und wenn Business-Objekte enthalten sind, diese in die Transaktion miteinbezögest.

herbivore
private Nachricht | Beiträge des Benutzers
codester
myCSharp.de - Member



Dabei seit:
Beiträge: 20
Herkunft: Saarland

beantworten | zitieren | melden

Hier nochmal der komplette if-Block:


if (fi.FieldType.GetInterface("IEnumerable") != null)
          {
            if (fi.FieldType.IsGenericType)
            {
              try
                {
                  _dictFields[fi] = Activator.CreateInstance(fi.FieldType, fi.GetValue(this));
                }
              catch (Exception)
                { 
                    _dictFields[fi] = fi.GetValue(this);
                }
            }
            else
            {
              if (fi.FieldType.GetInterface("ICloneable") != null)
              {
                ICloneable L = (ICloneable)fi.GetValue(this);//Von diesem "(ICloneable)" vermute ich, dass es was mit Typkonversion zu tun hat... könnte aber auch sein, dass ich hier nen riesen Bock geschossen hab...
                _dictFields[fi] = L.Clone();
              }
              else
              {
                _dictFields[fi] = fi.GetValue(this);
              }
            }
           System.Collections.IEnumerable List=(System.Collections.IEnumerable)fi.GetValue(this);
           foreach (BusinessObject BO in List)
           {
             BO.StartTransaction();
           }
          }
          else
          {          
            _dictFields[fi] = fi.GetValue(this);
          }
Wir alle sind Untertanen unseres gütigen, weisen und unermesslich reichen Herrschers William Gates des Dritten
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo codester,

sieht doch ganz gut aus.

Allerdings wird foreach (BusinessObject BO in List) { ... knallen, sobald er das erste Objekt findet, dass kein BusinessObject ist. Besser wäre foreach (Object obj in List) { if (obj is BusinessObject) { .... Außerdem müsstest du in der Schleife _StartTransaction verwenden.

herbivore
private Nachricht | Beiträge des Benutzers
codester
myCSharp.de - Member



Dabei seit:
Beiträge: 20
Herkunft: Saarland

beantworten | zitieren | melden

Zitat
Allerdings wird foreach (BusinessObject BO in List) { ... knallen, sobald er das erste Objekt findet, dass kein BusinessObject ist.

OK.

Werde das neue BusinessObject jetzt mal an ein paar Sachen testen und sehen obs auch wirklich geht. Dass es mit dem Dialogfeld weiter Probleme geben wird, ist jetzt schon klar, denn die Auflistung, für die ich das Rollback gegebenenfalls anwenden will, ist vom Typ ListBox.ObjectCollection(wieso gibt es solche Extrawürste?). Der implementiert kein ICloneable und ist auch nicht generisch. Ich werd mal versuchen, ob ich das durch ein bischen Erben hinkriege...
Wir alle sind Untertanen unseres gütigen, weisen und unermesslich reichen Herrschers William Gates des Dritten
private Nachricht | Beiträge des Benutzers
codester
myCSharp.de - Member



Dabei seit:
Beiträge: 20
Herkunft: Saarland

beantworten | zitieren | melden

OK, mein Dialogfeld ist jetzt fertig:

Mit der übergebenen Auflistung belege ich die Eigenschaft eines Erben der BusinessObject-Klasse, so dass die Aktionen Hinzufügen, Entfernen und Verschieben eines Elementes rückgängig gemacht werden können.

Aber beim Rückgängigmachen von Änderungen an den Eigenschaften von Elementen, konnte mir BusinessObject nicht helfen, obwohl ich drei Tage alle möglichen Varianten ausprobiert habe.
Ich habe mich dann entschlossen, das Problem ungelöst zu lassen(hätte ich schon nach einem Tag machen sollen) : Die Klasse und einige ihrer Member sind abstract, so dass der Benutzer der Klasse sich selbst darum kümmern muss, dass der Status eines Elementes gespeichert wird und wie das RollBack vonstatten geht. Das hat außerdem den Vorteil, dass nicht pauschal alle Eigenschaften der Elemente "konserviert" werden müssen, sondern nur die, die auch wirklich bearbeitet werden.
Ich danke für die Hilfe!
Wir alle sind Untertanen unseres gütigen, weisen und unermesslich reichen Herrschers William Gates des Dritten
private Nachricht | Beiträge des Benutzers
codester
myCSharp.de - Member



Dabei seit:
Beiträge: 20
Herkunft: Saarland

beantworten | zitieren | melden

Hier noch mal der gesamte Code von BusinessObject, nachdem ich die Änderungen vorgenommen habe, sonst muss man sich das mühsam zusammenklauben:


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
//*****************************************************************************
  abstract class BusinessObject
  {
    //--------------------------------------------------------------------------

    // In welcher Transaktion das Objekt enthalten ist
    private Guid _guidTransaction = Guid.Empty;

    // Bei welchem Objekt die Transaktion begonnen wurde
    private BusinessObject _boRoot = null;

    // Alle Objekte in der Transaktion; nur beim WurzelObjekt gesetzt
    private List<BusinessObject> _listScope = null;

    // Der gespeicherte Zustand des Objekts
    private Dictionary<FieldInfo, Object> _dictFields = null;



    //==========================================================================
    public void StartTransaction()
    {
      if (_listScope != null)
      {
        throw new Exception("Keine geschachtelten Transaktionen erlaubt.");
      }

      _listScope = new List<BusinessObject>();

      try
      {
        _StartTransaction(0, Guid.NewGuid(), this);
      }
      catch (Exception)
      {
        foreach (BusinessObject boCurr in _listScope)
        {
          boCurr._guidTransaction = Guid.Empty;
          boCurr._boRoot = null;
          boCurr._dictFields = null;
        }
        _listScope = null;
        throw;
      }
    }

    //==========================================================================
    private void _StartTransaction(int iLevel,
                                    Guid guidTransaction,
                                    BusinessObject boRoot)
    {
      if (_guidTransaction != Guid.Empty)
      {
        if (_guidTransaction == guidTransaction)
        {
          return; // zyklischen Struktur, Objekt schon besucht
        }
        throw new Exception("Objekt ist schon in einer anderen "
                           + "Transaktion enthalten.");
      }

      boRoot._listScope.Add(this);
      _guidTransaction = guidTransaction; // als besucht kennzeichnen
      _boRoot = boRoot;
      _dictFields = new Dictionary<FieldInfo, Object>();

      FieldInfo[] afi;
      List<FieldInfo> listfiAll = new List<FieldInfo>();
      BusinessObject boChild;

      Type t;

      // Die Schleife ist notwending, weil man sonst nicht an die privaten
      // Felder der Oberklassen kommt.
      for (t = GetType(); t != typeof(BusinessObject); t = t.BaseType)
      {
        afi = t.GetFields(BindingFlags.GetField
                         | BindingFlags.Instance
                         | BindingFlags.NonPublic
                         | BindingFlags.DeclaredOnly
                         | BindingFlags.Public); // nur zur Sicherheit
        foreach (FieldInfo fi in afi)
        {
#if SW_VERBOSE
            Console.WriteLine (new String (' ', 3 * iLevel)
                               + fi.DeclaringType + "." + fi.Name);
#endif
          if (fi.FieldType.GetInterface("IEnumerable") != null)//mit Aulistungen soll speziell verfahren werden
          {
            if (fi.FieldType.IsGenericType)//wenn Auflistung generisch, versuchen, sie per Kopier-Konstruktor zu kopieren.
            {
              try
                {
                  _dictFields[fi] = Activator.CreateInstance(fi.FieldType, fi.GetValue(this));
                }
              catch (Exception)
                {
                  if (fi.FieldType.GetInterface("ICloneable") != null)//wenn generische Auflisung Cloneable, flach kopieren
                  {
                    ICloneable L = (ICloneable)fi.GetValue(this);
                    _dictFields[fi] = L.Clone();
                  }
                  else//ansonsten normal kopieren
                  {
                    _dictFields[fi] = fi.GetValue(this);
                  }
                }
            }
            else//wenn Auflistung nicht generisch, nachsehen, ob sie Cloneable ist
            {
              if (fi.FieldType.GetInterface("ICloneable") != null)//wenn nicht generische Auflisung Cloneable, flach kopieren
              {
                ICloneable L = (ICloneable)fi.GetValue(this);
                _dictFields[fi] = L.Clone();
              }
              else//ansonsten normal kopieren
              {
                _dictFields[fi] = fi.GetValue(this);
              }
            }
           System.Collections.IEnumerable List=(System.Collections.IEnumerable)fi.GetValue(this);
           foreach (object O in List)//Alle BusinessObjects in der Auflistung in die Transaction aufnehmen
           {
             if (O is BusinessObject)
             {
               BusinessObject BO = (BusinessObject)O;
               BO._StartTransaction(iLevel+1,guidTransaction,boRoot);
             }
           }
          }
          else
          {          
            _dictFields[fi] = fi.GetValue(this);
          }

        }
        listfiAll.AddRange(afi);
      }

      // Rekursiver Abstieg
      foreach (FieldInfo fi in listfiAll)
      {
        if (fi.FieldType.IsSubclassOf(typeof(BusinessObject)))
        {
#if SW_VERBOSE
            Console.WriteLine ("=> " + new String (' ', 3 * iLevel)
                               + fi.DeclaringType  + "." + fi.Name);
#endif
          boChild = (BusinessObject)fi.GetValue(this);
          if (boChild != null)
          {
            boChild._StartTransaction(iLevel + 1, guidTransaction, boRoot);
          }
        }
      }
    }

    //==========================================================================
    public void CommitTransaction()
    {
      if (_guidTransaction == Guid.Empty)
      {
        throw new Exception("Objekt ist in keiner Transaktion enthalten.");
      }

      if (_listScope == null)
      {
        throw new Exception("Die Transaktion wurde nicht bei diesem "
                           + "Objekt begonnen");
      }

      foreach (BusinessObject boCurr in _listScope)
      {
        boCurr._guidTransaction = Guid.Empty;
        boCurr._boRoot = null;
        boCurr._dictFields = null;
      }
      _listScope = null;
    }

    //==========================================================================
    public void RollbackTransaction()
    {
      if (_guidTransaction == Guid.Empty)
      {
        throw new Exception("Objekt ist in keiner Transaktion enthalten.");
      }

      if (_listScope == null)
      {
        throw new Exception("Die Transaktion wurde nicht bei diesem "
                           + "Objekt begonnen");
      }

      foreach (BusinessObject boCurr in _listScope)
      {
#if SW_VERBOSE
         Console.WriteLine (boCurr.GetType ());
#endif
        foreach (FieldInfo fi in boCurr._dictFields.Keys)
        {
#if SW_VERBOSE
            Console.WriteLine ("..."  + fi.DeclaringType + "." + fi.Name);
#endif
          fi.SetValue(boCurr, boCurr._dictFields[fi]);
        }
        boCurr._guidTransaction = Guid.Empty;
        boCurr._boRoot = null;
        boCurr._dictFields = null;
      }
      _listScope = null;
    }

    //==========================================================================
    ~BusinessObject()
    {
      if (_listScope != null)
      {
        RollbackTransaction();
      }
      else if (_boRoot != null)
      {
        _boRoot.RollbackTransaction();
      }
    }
  }
Wir alle sind Untertanen unseres gütigen, weisen und unermesslich reichen Herrschers William Gates des Dritten
private Nachricht | Beiträge des Benutzers
be4all
myCSharp.de - Member



Dabei seit:
Beiträge: 68

beantworten | zitieren | melden

Sorry, dass ich das Thema wieder rauskrame ;-)

Guter Thread. Habe diese Klasse nun mal ausprobiert... funktioniert soweit ganz wunderbar - genau das was ich schon lange gesucht habe.

Nun wollte ich diese Klasse im Zusammenhang mit ADO.NET for Entities und LINQ verwenden. Wie kann ich denn nun meine automatisch generierten Klassen (z.B. Klasse "Person") als BusinessObjects definieren? C# unterstützt ja leider keine Mehrfachvererbung... :(
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von be4all am .
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo be4all,

die einzige Alternative zu Mehrfachvererbung (da wo man wirklich Mehrfachvererbung brauchen würde), die ich kenne, die immer funktioniert, die aber leider etwas umständlich ist, ist eine der Oberklassen durch ein Interface und eine Hilfsklasse zu ersetzen.

Nimm an, du hast die Klassen

public class A         { public void Ma () { /* tue was */ } }
public class B         { public void Mb () { /* tue was */ } }

und willst einen Ersatz für

public class C : A, B { ...

finden, dann würde das schematisch so aussehen:

public interface IB    {        void Mb ();                  }
public class C : A, IB { public void Mb () { _b.Mb (); } private B _b = new B (); }

Man schafft also eine Interface, dass alle öffentlichen Methoden (Member) von B enthält und degradiert B zur Hilfsklasse, die benutzt wird, um die Interface-Methode in C durch den Aufruf der entsprechenden Methode in B zu implementieren.

Dadurch, dass man man das für jede Methode (jeden Member) machen muss, ist das eben etwas umständlich. Dafür funktioniert es nach festem Schema.

Wenn du auf die generierten Klassen selbst keinen Einfluss hast, dann musst du ggf. noch eine weitere Unterklasse einführen.

public class Person { ... } // kann man nicht beeinflussen
public class TransactionalPerson : Person, ITransactional 

wobei TransactionalPerson die neue Unterklasse ist, ITransactional das neue Interface und BusinessObject zur Hilfsklasse wird.

herbivore
private Nachricht | Beiträge des Benutzers
be4all
myCSharp.de - Member



Dabei seit:
Beiträge: 68

beantworten | zitieren | melden

Ich kann nicht ganz folgen...? Sorry...

Ich habe folgende automatisch generierte Klasse (einfache Klasse) mit einer Eigenschaft Nachname und ID:


public partial class person : global::System.Data.Objects.DataClasses.EntityObject
{
     public static person Createperson(int id) { ... }
     public int ID { get { ... } { set { ... } }
     private int _ID;
     partial void OnIDChanging(int value);
     partial void OnIDChanged();     

     public string Nachname { get { ... } { set { ... } }
     private string _Nachname;
     partial void OnNachnameChanging(string value);
     partial void OnNachnameChanged();
}

Nun muss ich ja person von BusinessObject ableiten, um meine Methoden StartTransaction, CommitTransaction und RollBackTransaction für ein person-Object zur Verfügung zu stellen.

Was ist mit eventuell vorhandenen Listen oder Objekten, die auch wieder BusinessObject implementiert haben müssten (bezogen auf Klasse person)?

Kannst du mir das bitte nochmals anhand eines Beispiels (in Anlehnung an der Klasse person) demonstrieren?

Womöglich macht die Verwendung von ADO.NET Entities oder LINQ TO SQL im Zusammenhang mit BusinessObject wenig Sinn. Ich habe schließlich nicht nur eine Klasse, die BusinessObject implementieren müsste...

Danke dir!
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo be4all,
Zitat
Kannst du mir das bitte nochmals anhand eines Beispiels (in Anlehnung an der Klasse person) demonstrieren?
das Beispiel für Person steht doch schon in meinem Beitrag.

herbivore
private Nachricht | Beiträge des Benutzers
be4all
myCSharp.de - Member



Dabei seit:
Beiträge: 68

beantworten | zitieren | melden

OK, ich habe nun deinen Post nachvollziehen können. Ich habe es nun so implementiert, aber es funktioniert leider nicht so wie es soll - eigentlich gar nicht.

Hier der Original Code, welcher funktioniert:


    public class myObject : BusinessObject
    {
        private int Id { get; set; }
        public string Nachname { get; set; }
        public string Vorname { get; set; }
        public string PLZ { get; set; }
        public string Wohnort { get; set; }
        public myBeruf Beruf { get; set; }
        public List<myHobby> Hobbys { get; set; }

        public myObject()
        {
            //Do nothing.
        }

        public myObject(string nachname, string vorname, string plz, string wohnort, myBeruf beruf, List<myHobby> hobbys)
        {
            Nachname = nachname;
            Vorname = vorname;
            PLZ = plz;
            Wohnort = wohnort;
            Beruf = beruf;
            Hobbys = hobbys;
        }
    }

   public class myHobby : BusinessObject
    {
        private int Id { get; set; }
        public string Bezeichnung { get; set; }

        public myHobby()
        {
            //Do nothing.
        }
        
        public myHobby(string bezeichnung)
        {
            Bezeichnung = bezeichnung;
        }

        public override string ToString()
        {
            return this.Bezeichnung+" ("+this.Id+")";
        }
    }

    public class myBeruf : BusinessObject
    {   
        public int Id { get; set; }
        public string Bezeichnung { get; set; }

        public myBeruf()
        {
            //Do nothing.
        }

        public myBeruf(int id, string bezeichnung)
        {
            Id = id;
            Bezeichnung = bezeichnung;
        }

        public override string ToString()
        {
            return this.Bezeichnung + " ("+this.Id+")";
        }
    }

Funktioniert soweit sehr gut, auch mit der Liste public List<myHobby> Hobbys.

Wie bereits erwähnt, möchte ich nun aber myObject, myHobby und myBeruf nicht von BusinessObject ableiten. Deshalb dein Lösungsvorschlag, den ich wie folgt implementiert habe:


    public class myHobby { ... }

    public class myBeruf { ... }

    public class myObject
    {
        // ...
        public TMyBeruf Beruf { get; set; }
        public List<TMyHobby> Hobbys { get; set; }

        //public myObject()

        public myObject(string nachname, string vorname, string plz, string wohnort, TMyBeruf beruf, List<TMyHobby> hobbys)
        {
            //...
        }
    }


    // Interface
    public interface ITransactional
    {
        void StartTransaction();
        void CommitTransaction();
        void RollbackTransaction();
    }

    public class TMyObject : myObject, ITransactional
    {
        private BusinessObject bObj = new BusinessObject();

        public void StartTransaction() { bObj.StartTransaction(); }
        public void CommitTransaction() { bObj.CommitTransaction(); }
        public void RollbackTransaction() { bObj.RollbackTransaction(); }
    }

    public class TMyBeruf : myBeruf, ITransactional
    {
        private BusinessObject bObj = new BusinessObject();

        public void StartTransaction() { bObj.StartTransaction(); }
        public void CommitTransaction() { bObj.CommitTransaction(); }
        public void RollbackTransaction() { bObj.RollbackTransaction(); }
    }

    public class TMyHobby : myHobby, ITransactional
    {
        private BusinessObject bObj = new BusinessObject();

        public void StartTransaction() { bObj.StartTransaction(); }
        public void CommitTransaction() { bObj.CommitTransaction(); }
        public void RollbackTransaction() { bObj.RollbackTransaction(); }
    }

Wenn ich mit TMyHobby, TMyBeruf und TMyObject arbeite, funktioniert das ganze Rollback etc. nicht mehr... auch nicht bei einfachen Properties wie "Nachname" o.ä...
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo be4all,

zum einen musst du dafür sorgen, dass im laufenden Programm überall Objekte vom Typ TMyObject, TMyBeruf usw. erzeugt werden und keine Objekte vom Typ MyObject, MyBeruf usw.

Zum anderen musst du den Code von BusinessObject so ändern, dass er an allen relevanten Stellen mit dem Typ ITransactional statt BusinessObject arbeitet. Ob man dass durch einen globales Ersetzen von BusinessObject durch ITransactional erreichen kann, weiß ich nicht. Es könnte sein, dass es Stellen gibt, an deren weitere Änderungen erforderlich sind, weil BusinessObject eine Klasse und ITransactional ein Interface ist.

herbivore
private Nachricht | Beiträge des Benutzers