Implementacja interfejsy i typy generyczne

0

Witam. trafiłem na takie zadanie:screenshot-20210226211209.png A tutaj jest jego kontynuacja:screenshot-20210226211331.png . Udało mi się stworzyć pierwszą czesc zadania, ale w drugiej się pojawiają schody. Prosiłbym, aby ktos mógł ocenic poziom tego zadania i wytłumaczył mi jak zaimplementować interfejs IEanumerable<T> ,dlaczego w konstruktorze? miałem problem z implementacją ICloneable ,ale nie wiem czy w końcu jest ok? bo działać działa, ale bardzo długo się meczyłem bo myslałem ,ze trzeba zrobić tzw "Głębokie kopiowanie" a ,gdy już siły nie miałem to się okazało ,ze wystarczyło płytkie i tego też nie rozumiem. Dostałem wskazówkę od kolegi, aby składowe klasy ,które reprezentują stan obiektu deklarować w osobnej klasie niż metody, które wykonują operacje na nich (proszę o komentarz) . Klasa druzyna:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
namespace RPG
{
    class Druzyna : ICloneable
    {
       private List<IPostac> druzyna;
     private string nazwa;
//        dodaj konstruktor przujmujący w argumencie kolekcję IEnumerable<IPostac>,
//zaimplementuj interfejs IEnumerable<T>, tak aby możliwe było iterowanie elementów drużyny za pomocą pętli foreach,
     
            public Druzyna(string n)
        {
                      nazwa = n;
            druzyna = new List<IPostac>();
        }
        public void Dodaj(IPostac p)
        {
            druzyna.Add(p);
        }
        public int Suma()
        {
            int moc = 0;
            foreach  (IPostac item in druzyna)
            {
                moc += item.Moc();
            }
            return moc;
        }
     public IEnumerator GetEnumerator()
        {
            return druzyna.GetEnumerator();
        }
    
        public void Wyswietl()
        {
          
            foreach (IPostac item in druzyna)
            {
                Console.WriteLine(item.ToString());
            }
        
        }
      

        public object Clone()
        {
            return MemberwiseClone();
        }
    }
}

Przepraszam za taki burdel w kodzie. Jak będzie trzeba to postaram sie troche posprzatac:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;

namespace RPG
{


    class Program
    {
        static void Main(string[] args)
        {
            Mag m1 = new Mag();
            Console.WriteLine(m1.pkt(-45));
            Console.WriteLine(m1.ToString());
            Console.WriteLine(m1.pkt(5));
            Console.WriteLine(m1.ToString());
            Console.WriteLine("-----------------\n");
            Mag m2 = new Mag("Michal", 66, 23);
            Console.WriteLine(m2.ToString());
            Console.WriteLine("-----------------\n");
            Wojownik w = new Wojownik();
            w.pkt(5);
            Console.WriteLine(w.ToString());
            Mag bohater1 = new Mag();
            Mag bohater2 = new Mag("xyz", 10, 5);
            Wojownik bohater3 = new Wojownik();
            Wojownik bohater4 = new Wojownik("kamil", 10);

            Console.WriteLine("\nTworze druzyne\n");

            Druzyna druzyna = new Druzyna("Druzyna pierscienia");
            druzyna.Dodaj(bohater1);
            druzyna.Dodaj(bohater2);
            druzyna.Dodaj(bohater3);
            druzyna.Dodaj(bohater4);
           // druzyna.Wyswietl();
            Console.WriteLine("\nMoc druzyny: ------------------------");
            Console.WriteLine(druzyna.Suma());
            Console.WriteLine("\n");
            
            foreach (IPostac item in druzyna)
            {
                Console.WriteLine("Imie: {0}", item.Nazwa);
                Console.WriteLine(item);
            }
            Console.WriteLine("\n");
            Console.WriteLine("\n");
            //IEnumerator i = druzyna.GetEnumerator();
            //i.MoveNext();
            //Mag m = (Mag)i.Current;
            //Console.WriteLine("Imie : {0},moc {1}", m.Nazwa, m.Sila);

           
            Console.WriteLine("Nowa sklonowana drużyna:");

            Druzyna x;//= new Druzyna("Klon");
            x= (Druzyna)druzyna.Clone();
            foreach (IPostac item in x)
            {
                Console.WriteLine(item);
            }
            if(Object.ReferenceEquals(druzyna, x))
                Console.WriteLine("Referencje odwołuja się do tego samego obiektu"); 
     else
                Console.WriteLine("Referencje nie odwołuja się do tego samego obiektu"); //To zostaje wykonane

            //Coś takiego mi się wczesniej pokazywało????===>> System.InvalidCastException: „Nie można rzutować obiektu typu 'System.Collections.Generic.List`1[RPG.IPostac]' na typ 'RPG.Druzyna'.”

            Console.ReadKey();
        }
    }
}
0

No to jednak będziesz musiał trochę posprzątać, ciężko się czyta.
interfejs IEnumerable implementuje tylko jedną metodę: public IEnumerator GetEnumerator()

Czy chodzi o coś takiego?
screenshot-20210226224249.png

A jeżeli chodzi o implementację IEnumerable<T> to musiałbyś całą klasę przerobić:
https://cezarywalenciuk.pl/blog/programing/yield-sowo-kluczowe--uatwienie-implementacji-ienumerablelttgt

0

@gswidwa1: Dzięki wielkie za odpowiedź! Generalnie korzystam z ksiązki "Jezyk C# 6.0 i platforma .NET 4.6" i z "C# 7.0 Kompletny przewodnik dla praktyków" i wiem ,ze interfejs IEnumerable posiada jedną metodę, która zwraca referencje do kolejnego interfejsu IEnumerator, ale to tylko teoria :( jestem przed rozpoczęciem delegatów i zdarzeń i postanowiłem, że warto zrobić kilka zadanek, więc zacząłem szukać i w sumie zdecydowaną większość zrobiłem z tych, które znalazłem na stronach różnych uczelni. to zadanie wydaje mi się najciekawsze i odbiegające poziomem od reszty. Zadając pytanie czy "składowe klasy ,które reprezentują stan obiektu deklarować w osobnej klasie niż metody, które wykonują operacje na nich" miałem w głowie czy tutaj w przykładzie jest odpowiednio hermetyzacja zachowana? Od kolegi ,który programuje w jęz. java otrzymałem wiadomość: "masz klase ktora nazywa sie druzyna ale masz w niej operacje nie jest to zgodne z zasadami SOLID. Twoj team Druzyna powinno byc modelem transportowym tzw POJO a operacje powinne byc wydzielone do osobnego service ktory bedzie "pracowac" na tym obiekcie " i jak się ma to do C#? Jeszcze raz dzięki wielkie za pomoc

0

@gswidwa1: I wgl. zastanawiam się ,gdzie i jak szukać zadanek... Znalazłem fajne kiedyś ,gdzie było zadanie i diagram UML co mnie odciążało od tego ,gdzie co i jak. Zastanawiam się na jakim poziomie zadania muszę robić ,aby pójść krok dalej.. Jak wymyślę sobie jakieś zadanie to mam problem, aby samemu to sobie rozplanować, np. "Robię klasę taką, ta dziedziczy po tej a ta po tej.." o zwykłą segregacje mi chodzi? Jak to wyglądało u Ciebie podczas nauki? to samo przychodzi? i skąd brałeś zadania?

0

Dla mnie ten kod jest w porządku. Bardzo czytelny

5

@bdub123: nie daj sobie wmówić że klasa która przechowuje dane nie powinna mieć równiez metod.

0

Dzięki wielkie! :)

0

@kzkzg: Jeszcze jedno pytanko mam :D Staram się zrozumieć To zadanie i nie mogę. Przeczytałem wszystko co się dało na temat interfejsu IEnumerable i niestety nie rozumiem tego zadania :( ! Czesc zadania: "dodaj konstruktor przyjmujący w argumencie kolekcję IEnumerable<IPostac>,
zaimplementuj interfejs IEnumerable<T>, tak aby możliwe było iterowanie elementów drużyny za pomocą pętli foreach," --- tworzę dodatkowy konstruktor w klasie druzyna z argumentem ,gdzie jest kolekcja ,ale co dalej? jak mam druzyne stworzona w Programie to jak wywołać ten konstruktor? jakies rzutowanie? nie wychodzi mi wgl. Prosze o pomoc

0
public class MyClass : IEnumerable<IPerson>
    {
        private List<IPerson> people;
        public MyClass(IEnumerable<IPerson> people)
        {
            this.people = people.ToList();
        }
        public IEnumerator<IPerson> GetEnumerator()
        {
            return people.GetEnumerator();
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return people.GetEnumerator();
        }
    }

Tak w nawiasie. Powiedzcie mi, że to jest przypadek:
screenshot-20210227175051.png

Poczułem się, jakby vs mi chciał powiedzieć: "Ty głąbie, naucz się pisać" xD

0

No chodzi o to aby w przypadku podania kolekcji bohaterow jako argumentu podczas tworzenia nowego obiektu typu Druzyna, klasa ta automatycznie dodala je do listy aktualnych czlonkow druzyny czyli mniej wiecej:

Druzyna(IEnumerable<IPostac>enumerable){
var team = enumarable as List<IPostac>;
if(team!=null) this.team = team; 
else {
var enumerator = enumerable.getEnumerator();
while(enumerator.moveNext()){
this.team.add(enumerator.current)
}
}

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