[C#] Klasa Lista obiektów moich klas, pseudo zaprzyjaźnienie klas bez getterów i setterów.

0

Witam,
chciałbym się dowiedzieć jak w C# dokładnie działa integral(do zaprzyjaźnienia klas, nie chcę używać getterów i setterów), jak zaprzyjaźnić klaseA i Lista.

Dodatkowo chciałbym się zapytać czy w C# mogę zrobić liste/kolekcje klasy KlasaA, która będzie przechowywać elementy KlasyPochodnejA i KlasyPochodnejA2 itp.

//klasa bazowa
internal abstract class KlasaA // czy takie coś "zaprzyjaźnia" mi klasę? Jeśli nie jak to zrobić?
{
        int x;
        string n;
         
        public KlasaA()
        {
           DodajDane();
        }
         
        public virtual void DodajDane()
        {
        x=Convert.ToInt32(Console.ReadLine());
        n=Console.ReadLine();
        }
 
        public virtual void Pokaz()
        {
        Console.WriteLine("obiekt klasyA: " + x + " " + n + "\n");
        }
}
 
//klasa pochodna
class KlasaPochodnaA : KlasaA
{
        int z;
         
        public KlasaPochodnaA()
        {
           DodajDane();
        }
         
        public virtual void DodajDane()
        {
        z=Convert.ToInt32(Console.ReadLine());
        }
 
        public virtual void Pokaz()
        {
        Console.WriteLine(" "+ z+"\n");
        }
}
 
//klasa która ma być listą 
 
class Lista
{
        KlasaA lista = new List<KlasaA>() //nie wiem jak zrobić coś takiego, wyskakuje mi błąd
         
        public Lista()
        {
           ... 
        }
         
        public DodajElement()
        {
        ...
        }
}
0

W C# nie ma czegoś takiego jak friend (zakładam, że chodzi Ci o mechanizm z C++). Słowo kluczowe internal powoduje, że klasa nie jest widoczna poza assembly (czyli dll'ką).

Proponuję poczytać o słowach kluczowych w C# bo nie przekładają się bezpośrednio z C++.

0

No tak, chciałbym mieć dostęp do x,n,z w klasie Lista.
A jak prawidłowo utworzyć tą listę. Czy może zastosować coś innego?

1

W C# dostęp do pól realizuje się przez properties:

class SomeClass
{
    public int SomeInt { get; set; }
}

Z listą masz problem bo deklarujesz obiekt klasy KlasaA, a potem chcesz go zainicjalizować listą obiektów. To nie ma sensu. Zrób tak:

var list = new List<KlasaA>();
0

Ale typu var nie można używać w klasie przecież.

No właśnie chciałem uzyskać dostęp bez properties. Ale dzięki za odpowiedź :)

0
Isild napisał(a):

Ale typu var nie można używać w klasie przecież.

od kiedy? :D

0
john_klamka napisał(a):
Isild napisał(a):

Ale typu var nie można używać w klasie przecież.

od kiedy? :D

No próbowałem tak zrobić i wywalało mi błąd, spróbuje dokładnie twój kod wkleić i sprawdzę, może jakiś błąd robiłem.

Edit:
Ważność Kod Opis Projekt Plik Wiersz Stan pominięcia
Błąd CS0825 Kontekstowe słowo kluczowe „var” może występować tylko w deklaracji zmiennej lokalnej lub kodzie skryptu

2
Isild napisał(a):

Witam,
chciałbym się dowiedzieć jak w C# dokładnie działa integral(do zaprzyjaźnienia klas, nie chcę używać getterów i setterów), jak zaprzyjaźnić klaseA i Lista.

Nie, C# nie umożliwia tego rodzaju gwałtów na OOP.

Dodatkowo chciałbym się zapytać czy w C# mogę zrobić liste/kolekcje klasy KlasaA, która będzie przechowywać elementy KlasyPochodnejA i KlasyPochodnejA2 itp.

Tworząc kolekcję typu bazowego czyli KlasaA.

Poczytaj o OOP, w szczególności enkapsulacji i polimorfizmie.

0

var nie jest czymś a la wskaźnik na void z wbudowana de-referencja;)

To jest tak zwana dedukcja typu a nie obejście silnej statycznej typizacji.
Zauważ ze var age = 15;
to pisząc age. mamy metody z inta.

Nie można np var'a użyć w definicji funkcji np void foo(var costam);

var jedynie (dla mnie aż) zdejmuje konieczność wpisywania typu, szczególnie się przydaje przy pracy z
zewnętrznymi bibliotekami gdzie np: coś chcesz wyciągnąć z obiektu ale jeszcze nie wiesz dokładnie co albo jak:
var item = someObject.
i teraz sobie oglądasz metody/właściwości i wykonujesz wyboru.

Ciekawe jest tez używanie vara to typów anonimowych

Pozdrawiam
P

0
somekind napisał(a):
Isild napisał(a):

Witam,
chciałbym się dowiedzieć jak w C# dokładnie działa integral(do zaprzyjaźnienia klas, nie chcę używać getterów i setterów), jak zaprzyjaźnić klaseA i Lista.

Nie, C# nie umożliwia tego rodzaju gwałtów na OOP.

A refleksja? No, nie jest to C++ przyjaźń, ale można się odwołać do prywatnych pól i metod.

0
Juhas napisał(a):

A refleksja? No, nie jest to C++ przyjaźń, ale można się odwołać do prywatnych pól i metod.

Owszem, ale refleksja to nie jest mechanizm języka tylko API do uprawiania magii (albo czarnoksięstwa).

1
somekind napisał(a):
Juhas napisał(a):

A refleksja? No, nie jest to C++ przyjaźń, ale można się odwołać do prywatnych pól i metod.

Owszem, ale refleksja to nie jest mechanizm języka tylko API do uprawiania magii (albo czarnoksięstwa).

Tak, ale czasem się inaczej po prostu nie da albo inne rozwiązania nie mają sensu :)

1

@Juhas, refleksja się przydaje do analizy kodu (np. pobranie z klasy wszystkich właściwości oznaczonych jakimś atrybutem), albo do tworzenia jakichś frameworków/bibliotek działających na zasadzie konwencji i pozwalających na uniknięcie pisania masy nudnego kodu konfiguracyjnego. Bibliteki, które potrzebują refleksji to np. kontenery IoC, ORMy, automappery, serializery (np. z obiektów do CSV).

Jeśli ktoś stosuje refleksję do obchodzenia błędów w architekturze to nie jest to jej prawidłowe użycie. (Próby "zaprzyjaźniania" klas wynikają właśnie z błędów w architekturze.)

1
somekind napisał(a):

@Juhas, refleksja się przydaje do analizy kodu (np. pobranie z klasy wszystkich właściwości oznaczonych jakimś atrybutem), albo do tworzenia jakichś frameworków/bibliotek działających na zasadzie konwencji i pozwalających na uniknięcie pisania masy nudnego kodu konfiguracyjnego. Bibliteki, które potrzebują refleksji to np. kontenery IoC, ORMy, automappery, serializery (np. z obiektów do CSV).

Jeśli ktoś stosuje refleksję do obchodzenia błędów w architekturze to nie jest to jej prawidłowe użycie. (Próby "zaprzyjaźniania" klas wynikają właśnie z błędów w architekturze.)

Zgodzę się w 98%.

Przykład z życia. Bardzo wolno działający grid. Zwykły grid z Windows Forms. Wolno rysuje dane i strasznie skacze (żadnego customowego rysowania, tylko dane tekstowe). Więc trzeba włączyć mu podwójne buforowanie. Niestety z jakiegoś powodu właściwość DoubleBuffered jest protected. Więc teraz mam wybór. Albo tworzyć nową kontrolkę dziedziczącą po tym gridzie - tylko po to, żeby włączyć double buffered, albo po prostu użyć refleksji, żeby włączyć tą właściwość.

Co do friend... Friend powstał po to, bo programiści tego chcieli. Można się czepiać, że na pewno mają złą architekturę. Jednak C++ ma być szybki. A stosowanie skomplikowanych wzorców i mechanizmów może jednak kod spowalniać. W pewnych sytuacjach friend po prostu ułatwia życie. Wiem, że C# to nie C++, ale ja też miałem kilka sytuacji w życiu, gdzie friend by się przydał. A bez tego musiałem stosować jakieś dziwaczne zabiegi. I nie miało to związku ze złą architekturą, a po prostu z wymogami.

4

Więc teraz mam wybór. Albo tworzyć nową kontrolkę dziedziczącą po tym gridzie - tylko po to, żeby włączyć double buffered, albo po prostu użyć refleksji, żeby włączyć tą właściwość.

Ale wlasnie po to jest protected bys sobie podziedziczyl. Specjalnie ten grid ma ta wlasciwosc protected, ze jak bedziesz chcial sobie ja zmienic to powinienes napisac wlasnego grida na bazie tego istniejacego

A Refleksja tutaj jest totalnym overkillem i dodaje tylko zlozonosci do kodu

A odnosnie C++ to co napisales to po prostu bzdura... Pokaz mi realny przyklad gdzie architektura przeszkadza w C++ (zaznaczam. Realny!)

4
Juhas napisał(a):

Przykład z życia. Bardzo wolno działający grid. Zwykły grid z Windows Forms. Wolno rysuje dane i strasznie skacze (żadnego customowego rysowania, tylko dane tekstowe). Więc trzeba włączyć mu podwójne buforowanie. Niestety z jakiegoś powodu właściwość DoubleBuffered jest protected. Więc teraz mam wybór. Albo tworzyć nową kontrolkę dziedziczącą po tym gridzie - tylko po to, żeby włączyć double buffered, albo po prostu użyć refleksji, żeby włączyć tą właściwość.

Trzeba po prostu utworzyć nową kontrolkę, a nie dymać klasy refleksją.
Nowa kontrolka będzie miała nazwę, która będzie mówiła do czego służy i jaki jest cel jej istnienia. Jeśli ktoś będzie chciał wydajnego grida, to go użyje, i nie będzie problemu, że przypadkiem zapomniał odstawić czarnoksięstwa.

Co do friend... Friend powstał po to, bo programiści tego chcieli.

Programiści?
Raczej jeden leśny dziadek z Danii.

Można się czepiać, że na pewno mają złą architekturę. Jednak C++ ma być szybki. A stosowanie skomplikowanych wzorców i mechanizmów może jednak kod spowalniać

Zgoda. Ale czy friend rozwiązuje jakieś konkretne, mierzalne problemy wydajnościowe?

W pewnych sytuacjach friend po prostu ułatwia życie. Wiem, że C# to nie C++, ale ja też miałem kilka sytuacji w życiu, gdzie friend by się przydał. A bez tego musiałem stosować jakieś dziwaczne zabiegi. I nie miało to związku ze złą architekturą, a po prostu z wymogami.

Piszę w C# jakieś 12 lat i nigdy friend nie potrzebowałem. Jeśli nie opiera się swojej architektury na mutowaniu globalnego stanu, i umie się przekazywać dane między obiektami w normalny sposób, to takie cuda nie są potrzebne.

1
somekind napisał(a):

Trzeba po prostu utworzyć nową kontrolkę, a nie dymać klasy refleksją.
Nowa kontrolka będzie miała nazwę, która będzie mówiła do czego służy i jaki jest cel jej istnienia. Jeśli ktoś będzie chciał wydajnego grida, to go użyje, i nie będzie problemu, że przypadkiem zapomniał odstawić czarnoksięstwa.

Zgoda. Jednak ja potrzebowałem tego grida tylko w jednym miejscu i po prawdzie nie chciało mi się robić osobnej kontrolki. Wolałem wpisać sobie dwie linijki kodu ;)

Co do friend... Friend powstał po to, bo programiści tego chcieli.

Programiści?
Raczej jeden leśny dziadek z Danii.

A tego to już nie wiem. Wiem tylko, że on nienawidzi C++ ;)

Można się czepiać, że na pewno mają złą architekturę. Jednak C++ ma być szybki. A stosowanie skomplikowanych wzorców i mechanizmów może jednak kod spowalniać

Zgoda. Ale czy friend rozwiązuje jakieś konkretne, mierzalne problemy wydajnościowe?

Spójrz tu: http://www.cprogramming.com/tutorial/friends.html

Weźmy teraz przykład takiego Node'a. Normalnie drzewo musiałoby posłużyć się jakimś getterem - a jakby nie patrzeć wywołanie metody daje jednak jakiś narzut. W sytuacji, kiedy zależy nam na każdej milisekundzie (przypominam, że C++ ma być szybki) przy większej ilości danych czas już się wydłuży o niepotrzebny narzut na wykonanie metody. To mimo wszystko jest kilka operacji więcej.

Mimo, że przykład nie jest najlepszy, to pewnie będzie coś w ten deseń.

Tutaj też gościu fajnie pisze w odpowiedzi: https://softwareengineering.stackexchange.com/questions/132403/should-i-use-friend-classes-in-c-to-allow-access-to-hidden-members

W pewnych sytuacjach friend po prostu ułatwia życie. Wiem, że C# to nie C++, ale ja też miałem kilka sytuacji w życiu, gdzie friend by się przydał. A bez tego musiałem stosować jakieś dziwaczne zabiegi. I nie miało to związku ze złą architekturą, a po prostu z wymogami.

Piszę w C# jakieś 12 lat i nigdy friend nie potrzebowałem. Jeśli nie opiera się swojej architektury na mutowaniu globalnego stanu, i umie się przekazywać dane między obiektami w normalny sposób, to takie cuda nie są potrzebne.

A wyślę Ci później przykład kodu z opisem co chciałem osiągnąć.

1

Można zrobic friend'a, zagnieżdżając klasy jedna w drugiej.
Takie rozwiązanie się nie skaluje. ale jest sporadycznie użyteczne.

public class A
{
    private int a = 0;
    public class B
    {
        public void RapeOOP(A obj)
       {
              Console.WriteLine(obj.a);
       }
    }
}

```

Możesz też stworzyć interfejs do łamania enkapsuacji i przebiegle zaimplementować go Explicit 'e. Nie będzie wisiał  w Api przy normalniej pracy, a jak bedzie trzeba coś z hakować to może robic magie bez refleksji. 
0

Wielkie dzięki wszystkim za pomoc, teraz mam co studiować :D

Mam jeszcze tylko takie jedno pytanie, otóż nie wiem jak w mainie zadeklarować obiekt tej klasy

class Lista
{
        public List<KlasaA> lista = new List<KlasaA>();
 
        public Lista()
        {
           ... 
        }
 
        public DodajElement()
        {
        ...
        }
}

Używając samego

Lista lista;

wyskakuje mi komunikat

Użyto nieprzypisanej zmiennej lokalnej

2
var lista = new Lista();
2

Lista lista po prostu tworzy "miejsce" na obiekt typu Lista - ale jego samego nie. Musisz użyć konstruktora: Lista lista = new Lista(). Konstruktor bezparametrowy jest tworzony automatycznie dla każdej klasy.

0

Chciałbym się jeszcze podpytać czy w c# jest taka funkcja, która przeszukuje listę obiektów po danym parametrze, np nazwie i zwraca go tak żebym mógł go zedytować?
Znalazłem wyrażenie lambda, ale nie do końca rozumiem jej istoty.
Do wyszukania elementu w liście używam funkcji FindIndex, ale potem nie wiem jak mam skorzystać z indeksu, żeby zedytować obiekt.

lista.FindIndex(x => x.marka == nazwa)

W c++ rozwiązałem to tak

for (auto it : lista)
		{
			if ((it->marka).compare(nazwa) == 0)
			{
				system("CLS");
				it->Pokaz();

				std::cout << "Czy to ten obiekt?(1-tak ten, 0-nie)" << endl;
				czy = getch();

				if (czy == '1')
				{
					system("PAUSE");
					return it;
				}
			}
		}
1

Do przeszukiwania kolekcji w c# generalnie używa się Linq. Poczytaj o metodach Where i FirstOrDefault - na początek Ci wystarczą.

0

Coś tam poczytałem i znalazłem z Linqiem i znalazłem coś co niby wydaje się proste, ale nie wyświetla mi tego co chcę.

Console.WriteLine("podaj marke i model obiektu  którego chcesz wyświetlić: ");
            Console.ReadLine();
            string mark = Console.ReadLine();
            string mod = Console.ReadLine();

            var querry = lista.Select(n => n).Where(n => n.marka == mark).Where(n => n.model == mod).ToList();

            foreach (var obiekt in querry)
            {
                Console.Write(obiekt + " ");
            }

Wyświetla mi się wtedy nazwa mojego projektu.

Edit.
Mogę jeszcze w tym temacie zadawać takie pytania czy powinienem założyć nowy temat? Nie chcę robić spamu :)

2

Nie projektu tylko klasy. Jak wyrzucasz cały obiekt do Console.WriteLine, to używana jest metoda ToString, która domyślnie zwraca właśnie nazwę klasy.
Wyświetl wartość konkretnej właściwości albo przeciąż ToString w swojej klasie.

A tak poza tym, to wystarczy Ci jedno Where z koniunkcją, dwa użycia tej metody nigdy nie są potrzebne.

0

A jeszcze jak za pomocą LINQa usówać obiekty z listy?

 Console.WriteLine("podaj marke obiektu, który chcesz usunąć: ");
            Console.ReadLine();
            string mark = Console.ReadLine();

            var querry = lista.Select(n => n)
                .Where(n => n.marka == mark)
                .ToList();

            foreach (var obierkt in querry)
            {
                obiekt.Pokaz();
                Console.WriteLine("czy chcesz usunąć ten obiekt?(1-tak/0-nie)");
                string odp = Console.ReadLine();
                if(odp == "1")
                {
                    //tutaj nie wiem jak to usunąć, znaczy czy poprawnie to robię
                    lista.Remove(obiekt);
                }
            }

Jeszcze sobie przypomniałem, czy mogę tak dodawać do mojej listy:

                case "1":
                    lista.Add(new KlasaPochodnaA());
                    break;
                case "2":
                    lista.Add(new KlasaPochodnaB());
                    break;

pomimo że mam liste

public List<KlasaA> lista = new List<KlasaA>();
0

Do usuwania masz metodę RemoveAll. A na pytanie o to czy możesz dodać do listy pochodne odpowie Ci kompilator.

1
Isild napisał(a):

A jeszcze jak za pomocą LINQa usówać obiekty z listy?

Nie możesz. LINQ, jak sama nazwa wskazuje służy do zapytań, anie modyfikowania danych.

0

Remove jest metodą listy nie linq, ale tak właśnie usuwa się z niej elementy.
Odnośnie dodawania: jeżeli obie klasy pochodne faktycznie dziedziczą po KlasaA to jest to możliwe

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