none
Wie deklariert man eine Membervariable automatisch mit dessen Basisklasse? RRS feed

  • Frage

  • Hallo zusammen,

    ich habe ein kleines Problem und hoffe Ihr könnt mir dabei weiterhelfen. Ich habe zwei Klassen eine Klasse "Parent" und eine Klasse "Children".

    In der "Parent"-Klasse befindet sich eine Liste von Member des Typs "Children".

    In der "Children"-Klasse befindet sich ein Member Owner des Typs "Parent".

    Ich habe nun in meiner Main-Funktion eine Variable "mother" vom Typ "Parent". Möchte ich dieser nun ein "Children" durch die Add-Methode hinzufügen, so soll automatisch der Owner des Childrens auf die Variable "mother" gesetzt werden. Ich möchte den Owner nicht immer manuell setzen müssen! Momentan wird bei mir jedoch noch nichts gesetzt.

    Wie genau kann ich mein Problem lösen? Hier der Code:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    namespace Test{
        public class Children {
            private Parent _Owner;
            string _Test;
            public string Test
            {
              get { return _Test; }
              set { _Test = value; }
            }
            public Parent Owner {
                get { return _Owner; }
                set { _Owner = value; }
            }
            public Children(string eingabe) {
                Test = eingabe;
            }
        }
        public class Parent {
            private List<Children> _Members;
            public List<Children> Members {
                get { return _Members; }
                set { _Members = value; }
            }
            public Parent() {
                Members = new List<Children>();
            }
        }
        public class Program{
            static void Main(string[] args) {
                Parent mother = new Parent();
                mother.Members.Add(new Children("Child1"));
                try {
                    Console.WriteLine(mother.Members[0].Owner.ToString());
                } catch (NullReferenceException e) {
                    Console.WriteLine(e.ToString());
                }
                Console.ReadLine();
            }
        }
    }


    Er geht natürlich in die NullReferenceException und gibt die entsprechende Zeile aus. Setze ich  nun vor der Ausgabe

    mother.Members[0].Owner=mother;

    so kommt mein gewünschtes Ergebnis. Wie bereits gesagt, möchte ich das aber umgehen und durch die Add-Methode den "Owner" des hinzugefügten Members  automatisch auf "mother" setzten. Die Frage ist nur wie?

    Ich hoffe Ihr könnt mich verstehen und mir ggf. auch weiterhelfen.

    Sonntag, 16. September 2012 08:27

Antworten

  • Wenn du statt List<T> eine ObservableCollection<T> benutzt:

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using System.Data;
    using System.Linq;
    using System.Text;
    
    namespace Test{
        public class Children {
            private Parent _Owner;
            string _Test;
            public string Test
            {
              get { return _Test; }
              set { _Test = value; }
            }
            public Parent Owner {
                get { return _Owner; }
                set { _Owner = value; }
            }
            public Children(string eingabe) {
                Test = eingabe;
            }
        }
        public class Parent {
            private ObservableCollection<Children> _Members;
            public ObservableCollection<Children> Members {
                get { return _Members; }
                set { _Members = value; }
            }
            public Parent() {
                Members = new ObservableCollection<Children>();
                Members.CollectionChanged += Members_CollectionChanged;
            }
    
            void Members_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
            {
                if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
                {
                    foreach (Children child in e.NewItems)
                    {
                        child.Owner = this;
                    }
                }
                if (e.Action == NotifyCollectionChangedAction.Remove || e.Action == NotifyCollectionChangedAction.Replace)
                {
                    foreach (Children child in e.OldItems)
                    {
                        child.Owner = null;
                    }
                }
                       
            }
        }

    dann kannst du wie im obigen Beispiel das CollectionChanged-Ereignis benutzen, um die Verweise auf die Parent-Instanz zu setzen.


    MVP Data Platform Development My blog

    Sonntag, 16. September 2012 09:39
  • Als Ausweg könntest du für Children eventuell einen Konstruktor

      public Children(string eingabe, Parent owner)

      {

         Owner = owner;

         Name = eingabe;

      }

    definieren und diesen dann per

      mother.Members.Add(new Children("Child1", mother));

    aufrufen, die ObservableCollection und den CollectionChanged-Eventhandler brauchst du so allerdings nicht mehr.

     


    MVP Data Platform Development My blog

    Sonntag, 16. September 2012 14:12

Alle Antworten

  • Wenn du statt List<T> eine ObservableCollection<T> benutzt:

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using System.Data;
    using System.Linq;
    using System.Text;
    
    namespace Test{
        public class Children {
            private Parent _Owner;
            string _Test;
            public string Test
            {
              get { return _Test; }
              set { _Test = value; }
            }
            public Parent Owner {
                get { return _Owner; }
                set { _Owner = value; }
            }
            public Children(string eingabe) {
                Test = eingabe;
            }
        }
        public class Parent {
            private ObservableCollection<Children> _Members;
            public ObservableCollection<Children> Members {
                get { return _Members; }
                set { _Members = value; }
            }
            public Parent() {
                Members = new ObservableCollection<Children>();
                Members.CollectionChanged += Members_CollectionChanged;
            }
    
            void Members_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
            {
                if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
                {
                    foreach (Children child in e.NewItems)
                    {
                        child.Owner = this;
                    }
                }
                if (e.Action == NotifyCollectionChangedAction.Remove || e.Action == NotifyCollectionChangedAction.Replace)
                {
                    foreach (Children child in e.OldItems)
                    {
                        child.Owner = null;
                    }
                }
                       
            }
        }

    dann kannst du wie im obigen Beispiel das CollectionChanged-Ereignis benutzen, um die Verweise auf die Parent-Instanz zu setzen.


    MVP Data Platform Development My blog

    Sonntag, 16. September 2012 09:39
  • Hallo Martin,

    danke für deine Antwort. Ich habe aber noch eine weitere Frage. Wenn ich in der Klasse "Children" einen ganz bestimmten "Namen" für die Kinder ausschließen möchte - den ich in meiner lokalen "Parent"-Variable - verwalte, so  bricht das Programm mit einer NullReferenceException ab

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using System.Linq;
    using System.Text;
    
    
    
    namespace Test{
        public class Children {
            private Parent _Owner;
            string _Name;
    
            public string Name
            {
              get { return _Name; }
              set {
                  if(!InvalidName())
                  _Name = value; 
              }
            }
    
            public Parent Owner {
                get { return _Owner; }
                set { _Owner = value; }
            }
    
            public Children(string eingabe) {
                Name = eingabe;
            }
    
            public bool InvalidName(){
                return Owner.NoName == Name ? false : true;
            }
    
        }
    
        public class Parent {
            private ObservableCollection<Children> _Members;
            string _NoName;
    
            public string NoName {
                get { return _NoName; }
                set { _NoName = value; }
            }
    
            public ObservableCollection<Children> Members {
                get { return _Members; }
                set { _Members = value; }
            }
    
            public Parent() {
                Members = new ObservableCollection<Children>();
                Members.CollectionChanged += Members_CollectionChanged;
            }
    
            void Members_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
                if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add) {
                    foreach (Children child in e.NewItems) {
                        child.Owner = this;
                    }
                }
                if (e.Action == NotifyCollectionChangedAction.Remove || e.Action == NotifyCollectionChangedAction.Replace) {
                    foreach (Children child in e.OldItems) {
                        child.Owner = null;
                    }
                }
    
            }
    
        }
    
        public class Program{
    
            static void Main(string[] args) {
                Parent mother = new Parent();
                mother.NoName = "TestName"; 
                try {
                    mother.Members.Add(new Children("Child1"));
                    Console.WriteLine(mother.Members[0].Name);
                } catch (NullReferenceException e) {
                    Console.WriteLine(e.ToString());
                }
                Console.ReadLine();
            }
        }
    }
    
    Nun eine weitere Frage: Gibt es eine einfache Möglichkeit, dass das Programm bereits bei der Deklaration diese Prüfung erfolgreich durchführen kann und meine erste Frage auch beantwortet ist? Es müsste wohl erst die Methode
    Members_CollectionChanged
    aufgerufen werden und anschließend die Prüfung erfolgen. Die Methode
    Members_CollectionChanged
    wird aber erst dann aufgerufen, wenn die Variable der ObservableCollection zugeordnet wird.

    Vielen Dank!

    Sonntag, 16. September 2012 13:10
  • Als Ausweg könntest du für Children eventuell einen Konstruktor

      public Children(string eingabe, Parent owner)

      {

         Owner = owner;

         Name = eingabe;

      }

    definieren und diesen dann per

      mother.Members.Add(new Children("Child1", mother));

    aufrufen, die ObservableCollection und den CollectionChanged-Eventhandler brauchst du so allerdings nicht mehr.

     


    MVP Data Platform Development My blog

    Sonntag, 16. September 2012 14:12
  • Hallo MartinKunze,

    Ich gehe davon aus, dass die Antworten Dir weitergeholfen haben.
    Solltest Du noch "Rückfragen" dazu haben, so gib uns bitte Bescheid.

    Grüße,
    Robert


    Robert Breitenhofer, MICROSOFT   Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip Entwickler helfen Entwickler“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.

    Dienstag, 25. September 2012 15:06
    Moderator