[C#] Projektowanie klas vs. istniejące klasy

0

Witam.
Pisząc aplikację napadła mnie pewna wątpliwość.

Potrzebuję zbudować klasę, która będzie przechowywała informacje pobrane z pliku xml o takiej budowie:

<?xml version="1.0" encoding="utf-8" ?>
<modules>
  <module name="module1">
    <class id="1" name="class1"/>
    <class id="2" name="class2"/>
    <class id="3" name="class3"/>
  </module>
  <module name="module2">
    <class id="1" name="class4"/>
    <class id="2" name="class5"/>
    <class id="3" name="class6"/>
  </module>
</modules>

Początkowo chciałem za pomocą metod z System.Xml wczytać dane i przechowywać je w pamięci za pomocą DataSet, gdzie każda z tabeli będzie reprezentowała jeden element z pliku o nazwie module a każdy wiersz jeden element o nazwie class. Dostęp poprzez publiczną właściwość DataTable.

Doszedłem do wniosku, że jest to chyba przesadne i mało profesjonalne podejscie. Postanowiłem zbudować klasy zagnieżdzone, zawierające akcesory, które będą pobierały wartości z datatable lub listy list<string>.

A wy jak projektujecie podobne problemy?
Będę wdzięczny za wszelkie wypowiedzi w tym temacie.

Pzdr

0

A to nie można zdeserializować?

0
somekind napisał(a)

A to nie można zdeserializować?

a możliwa jest deserializacja do kolekcji obiektów zawierajacych inne kolekcje?

0
projektowanie napisał(a)
somekind napisał(a)

A to nie można zdeserializować?

a możliwa jest deserializacja do kolekcji obiektów zawierajacych inne kolekcje?

Sprawdź?

0
Mendoza napisał(a)
projektowanie napisał(a)
somekind napisał(a)

A to nie można zdeserializować?

a możliwa jest deserializacja do kolekcji obiektów zawierajacych inne kolekcje?

Sprawdź?

Ok, jeśli tak, to mogę zdeserializować do DataTable. Myślę, że nie chciałbym udostępniać wszystkich składowych tej klasy, więc zdeserializowaną kolekcję bym zamienił na obiekt klasy ModuleInfo:

public class ClassInfo
    {
        private StringCollection sCol;
        public class StringCollection
        {
            private List<string> sList = null;
            public string this[int index]
            {
                get { return sList[index]; }
            }
            public void Add(string val)
            {
                if (sList != null) sList.Add(val);
                else{sList = new List<string>(); sList.Add(val);}
            }
            public int Count
            {
                get { return sList.Count; }  
            }
        }
        public ClassInfo()
        {
            sCol = new StringCollection();
        }
        public StringCollection Items
        {
            get { return sCol; }
        }

    }

    public class ModuleInfo
    {
        private ModuleCollection mCol;
        public class ModuleCollection
        {

            private List<ClassInfo> cList;
            public ClassInfo this[int index]
            {
                get { return cList[index]; }
            }
            public void Add(ClassInfo val)
            {
                if (cList != null) cList.Add(val);
                else { cList = new List<ClassInfo>(); cList.Add(val); }
            }
            public int Count
            {
                get { return cList.Count; }
            }
            
        }
        public ModuleInfo()
        {
            mCol = new ModuleCollection();
        }
        public ModuleCollection Modules
        {
            get { return mCol; }
        }
    }

Dopiero zaczynam zabawę z C#, więc jeśli by ktoś mógł rzucić okiem na klasy, które napisałem i powiedzieć, czy klasy sa hermetyczne i dobrze zaprojektowane oraz czy przechowywanie danych w takiej konstrukcji jest lepszym rozwiązaniem niż udostępnianie całej zdeserializowanej kolekcji i wszystkich jej składowych.

Z góry dzięki za pomoc.

0

Serializacja jest fajna póki robi dokładnie to co chcemy, lub jest nam to wszystko jedno.
Nagle potem okazuje się, że czegoś się zrobić nie da, albo wymaga to ogromnej gimnastyki.

Takiego XML-a można sobie zapisywać i odczytywać "ręcznie". Przynajmniej ma się dokładną kontrolę nad wyglądem XML-a:

using System;
using System.IO;
using System.Collections.Generic;
using System.Xml.Linq;

namespace serializacja
{
    public struct Klasa
    {
        public int id;
        public string name;
        public Klasa(int aid,string aname)
        {
            id = aid;
            name = aname;
        }
    }
    
    public class Modul : List<Klasa>
    {
        public string name;
        public Modul(string aname)
        {
            name = aname;
        }
     }

    public class ListaModulow:List<Modul>
    {
        public static ListaModulow FromXml(XDocument xml)
        {
            ListaModulow Result = new ListaModulow();
            foreach (var mnode in xml.Root.Elements("module"))
            {
                var modul = new Modul(mnode.Attribute("name").Value);
                foreach (var cnode in mnode.Elements("class"))
                    modul.Add(new Klasa(int.Parse(cnode.Attribute("id").Value),
                                        cnode.Attribute("name").Value));
                Result.Add(modul);
            }
            return Result;
        }
        public XDocument ToXml()
        {
            XDocument xml = new XDocument();
            var root=new XElement("modules");
            foreach (var modul in this)
            {
                var mnode = new XElement("module");
                mnode.Add(new XAttribute("name", modul.name));
                foreach (var klasa in modul)
                {
                    var cnode = new XElement("class");
                    cnode.Add(new XAttribute("id", klasa.id));
                    cnode.Add(new XAttribute("name", klasa.name));
                    mnode.Add(cnode);
                }
                root.Add(mnode);
            }
            xml.Add(root);
            return xml;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // tworzenie listy
            ListaModulow lista = new ListaModulow() {
                 new Modul("module1") {
                     new Klasa(1,"class1"),
                     new Klasa(2,"class2"),
                     new Klasa(3,"class3")},
                 new Modul("module2") {
                     new Klasa(1,"class4"),
                     new Klasa(2,"class5")
                 }};

            // tworzenie xml i zapis do pliku
            lista.ToXml().Save(@"plik.xml");
            
            // wyświetl plik xml
            Console.WriteLine("Zawartość pliku XML:");
            var xdoc = XDocument.Load(@"plik.xml");
            Console.WriteLine(xdoc);

            // odczyt z pliku
            var lista2=ListaModulow.FromXml(XDocument.Load(@"plik.xml"));

            // wyświetl zawartość odczytanej listy
            foreach (var m in lista2)
            {
                Console.WriteLine(m.name);
                foreach (var c in m)
                    Console.WriteLine("{0} - {1}",c.id,c.name);
            }
            Console.ReadKey();
        }
    }
}

Tylko gdy już jesteśmy przy LINQ, może się okazać że te klasy w ogóle nie będą potrzebne, bo można operować tworząc zapytania na obiektach xml-owych bezpośrednio…

projektowanie napisał(a)

public class ClassInfo
{
private StringCollection sCol;
public class StringCollection
To jest zbyteczne. Tworzysz kulawego wrappera na listę, jak możesz po prostu dziedziczyć po tej liście.
Jeśli nie chcesz, aby wszystkie pola były publiczne, możesz przenieść część kodu z metod FromXml/ToXml z powyższego przykładu do tych "pomniejszych" klas.

0

jesli mowily o resializacji xml to po co tworzyc jakis sztuczne metody, nie lepiej zaimplementowac System.Xml.Serialization.IXmlSerializable?
poza tym w przestrzeni nazw System.Xml.Serialization jest kilka atrybutow, ktorymi mozna opisac klasy i ich elementy jak maja sie serializowac, dzieki temu mozesz zapanowac nad procedem serializacji/deserializacji, a jak juz chcesz totalnie panowac nad tym procesem to implementujesz wspomniany IXmlSerializable

0

a jak juz chcesz totalnie panowac nad tym procesem to implementujesz wspomniany IXmlSerializable

To prawda, chociaż ostatnio zastosowałem coś podobnego do mojego przykładu powyżej - różniło się tym, że konwersja do/z xml była rozproszona po wszystkich klasach składowych (i tak powinno być) oraz odbywała się w operatorach explicit rzutujących do XElement i z powrotem. Nie trzeba wtedy tworzyć osobnego obiektu serializera, a zapis i odczyt stają się jednolinijkowe:

  ((XElement)jakisObiekt).Save("plik.xml");
  var jakisObiekt=(JakisTyp)(XDocument.Load("plik.xml").Root);

i już.

0
Azarien napisał(a)

Serializacja jest fajna póki robi dokładnie to co chcemy, lub jest nam to wszystko jedno.
Nagle potem okazuje się, że czegoś się zrobić nie da, albo wymaga to ogromnej gimnastyki.

Takiego XML-a można sobie zapisywać i odczytywać "ręcznie". Przynajmniej ma się dokładną kontrolę nad wyglądem XML-a

Tja... Ręcznie to można koło na nowo wymyślić.

Tak na szybko:

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;

namespace SerializationTest
{
    public class A
    {
        [XmlAttribute("id")]
        public int Id { get; set; }
        [XmlAttribute("name")]
        public string Name { get; set; }
    }

    [XmlType("module")]
    public class B
    {
        [XmlAttribute("name")]
        public string Name { get; set; }

        [XmlElement("class")]
        public List<A> ListOfA { get; set; }

        public B()
        {
            this.ListOfA = new List<A>();
        }
    }

    [XmlType("modules")]
    public class C : List<B>
    {
    }

    class Program
    {
        static void Main(string[] args)
        {

            #region serializacja
            B b1 = new B();
            b1.Name = "module1";
            b1.ListOfA.Add(new A() { Id = 1, Name = "class1" });
            b1.ListOfA.Add(new A() { Id = 2, Name = "class2" });
            b1.ListOfA.Add(new A() { Id = 3, Name = "class3" });

            B b2 = new B();
            b2.Name = "module2";
            b2.ListOfA.Add(new A() { Id = 1, Name = "class4" });
            b2.ListOfA.Add(new A() { Id = 2, Name = "class5" });
            b2.ListOfA.Add(new A() { Id = 3, Name = "class6" });

            C c = new C();
            c.Add(b1);
            c.Add(b2);

            using (FileStream fs = new FileStream(@"E:\Temp\plik.xml", FileMode.Create))
            {
                XmlSerializer ser = new XmlSerializer(typeof(C));
                ser.Serialize(fs, c);
            }
            #endregion

            #region deserialzacja
            C cd;
            using (FileStream fs = new FileStream(@"E:\Temp\plik.xml", FileMode.Open))
            {
                XmlSerializer ser = new XmlSerializer(typeof(C));
                cd = ser.Deserialize(fs) as C;

            }

            foreach (B b in cd)
            {
                Console.WriteLine(b.Name);
                foreach (A a in b.ListOfA)
                {
                    Console.WriteLine("{0} {1}", a.Id, a.Name);
                }
            }
            #endregion

            Console.ReadLine();
        }
    }
}

</b>

1 użytkowników online, w tym zalogowanych: 0, gości: 1