Wywołanie metody/konstruktora w innej klasie, to samo namespace

0

Witam

Mam kilka klas rozbitych po kilku plikach - wszędzie ten sam namespace.
Chcę w zdarzeniu wywołać metodę/konstruktor z innej klasy. Problem - nie mogę tego zrobić gdyż metoda/kontruktor jest "niewidoczna".

Przykład:

    class Metody
    {
        public string OdczytDanychZWagi(TcpClient klientTCP, byte[] WysylaneZapytanie)
        {
            // Wysyłka komunikatu do podłączonego serwera TCP
            NetworkStream stream = klientTCP.GetStream();
            stream.Write(WysylaneZapytanie, 0, WysylaneZapytanie.Length);

            // Otrzymanie odpowiedzi

            // Buffor na odpowiedz
            byte[] odpowiedz = new Byte[256];

            // String do przechowywania odpowiedzi w ASCII
            String responseData = String.Empty;

            // Odczyt danych z serwera
            Int32 bytes = stream.Read(odpowiedz, 0, odpowiedz.Length);
            responseData = System.Text.Encoding.ASCII.GetString(odpowiedz, 0, bytes);
            return responseData;
        }
        
        void WysylkaDoWagi(TcpClient klientTCP, byte[] KomunikatWysylany)
        {
            NetworkStream stream = klientTCP.GetStream();
            stream.Write(KomunikatWysylany, 0, KomunikatWysylany.Length);
        }
    }

Teraz klasa w której chciałbym wywołać:

public partial class Form1 : Form
    {
        public static TcpClient KlientTCP;
        public string IP = Properties.Settings.Default.AdresIP;
        public int nr_portu = Properties.Settings.Default.NrPortu;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            l_adresIP.Text = "Adres IP: " + Properties.Settings.Default.AdresIP;
            l_nrPortu.Text = "Nr portu: " + Properties.Settings.Default.NrPortu;
            l_nrWagi.Text = "Nr wagi:  " + Properties.Settings.Default.NrWagi;
            l_uruchomiono.Text = "Uruchomiono " + DateTime.Now;
           
            if (Properties.Settings.Default.CzyAutostart == 'T')
            {
                bt_polacz.Enabled = false;
                KlientTCP = new TcpClient();
                KlientTCP.Connect(IPAddress.Parse(IP), nr_portu);
                l_Autostart.Text = "Autostart: TAK";
                l_polaczono.Text = "Połączono: " + DateTime.Now;
                string odp = OdczytDanychZWagi(KlientTCP, OdczytZWagi.RejestrStatusu);
                tb_komunikaty.Text = odp;
                
            }

Kod

 string odp = OdczytDanychZWagi(KlientTCP, OdczytZWagi.RejestrStatusu);
                tb_komunikaty.Text = odp;

wywala błąd "The name 'OdczytDanychZWagi' does not exist in the current context"

Oczywiście próbowałem już z opcjami static / public itd.
Zadziała jeśli wpierw stworzę nową instancję klasy na zasadzie:

Metody metoda = new Metody();
string odp = metoda.OdczytDanychZWagi(KlientTCP, OdczytZWagi.RejestrStatusu);
tb_komunikaty.Text = odp;

Pytanie czy to konieczne?? Czy nie można prościej?? Chodzi mi o jaknajmniejszą ilość kodu. Czy takie ciągłe tworzenie nowych instancji klas nie wpłynie na wydajność aplikacji?

sformatowanie znaczników <code class="csharp"> - fp

1

Jeżeli chcesz wywołać metodę innej klasy, musisz albo mieć obiekt tej klasy, albo metoda musi być statyczna, wtedy wywołujesz ją przez NazwaKlasy.StatycznaMetoda(). Jeżeli próbowałeś z opcjami static/public itd., to coś źle próbowałeś.

0

Powinieneś użyć statycznych metod. Niestatycznych używa się, gdy chcesz zapamiętać jakieś dane w obiekcie.

public static class TcpReadHelper
{
   public static string Read(...)
   {
   //......
   }
}

private void Form1_Load(object sender, EventArgs e)
{
   //........
   TcpReadHelper.Read(...);
   //.......
}
0

Dzięki.

Faktycznie coś musiałem po drodze pomieszać.
Zrobiłem

public static string OdczytDanychZWagi(TcpClient klientTCP, byte[] WysylaneZapytanie) 

i teraz mogę już wywołać metodę

string odp = Metody.OdczytDanychZWagi(KlientTCP, OdczytZWagi.RejestrStatusu); 
0

Danie słowa static naprawi problem, ale prawda jest taka, że prawdziwy problem znajduje się między krzesłem a komputerem.
Poczytaj troszkę jak ma wyglądać Object Oriented Programing. Twój brak wiedzy w tej dziedzinie spowodował, że źle napisałeś te klasy, a brak słowa static jest tylko produktem ubocznym źle napisanych klas.
Przykładowo TcpClient powinien być polem klasy do komunikacji, którą nazwałeś z braku lepszego pomysłu "Metody" (za taką nazwę to się szubienica należy).

0

Dziękuję za budujące uwagi - dla wyjaśnienia:

  1. Piszę w dziale "Newbie" więc jestem osobą początkującą i się uczę
  2. TcpClient w sensie nawiązania komunikacji jest zdefiniowany w innej klasie - w klasie nawiązującej połączenie - dlaczego tutaj jest to błędne? Jak mam wysłać komunikat do urządzenia nie podając jakie to urządzenie?
  3. Nie nazwałem klasy "Metody" z braku lepszego pomysłu tylko że akurat dla mnie to jest nazwa czytelna w tym przypadku - nazewnictwo klas jest dowolne i ma być czytelne dla programisty więc nie bardzo rozumiem dlaczego należy mi się za to szubienica skoro ja sam piszę kod i to ja muszę się w nim odnaleźć ??

usunięcie cytowania całego poprzedniego posta - fp

0
dzilupl napisał(a):

nazewnictwo klas jest dowolne i ma być czytelne dla programisty więc nie bardzo rozumiem dlaczego należy mi się za to szubienica skoro ja sam piszę kod i to ja muszę się w nim odnaleźć ??

Dla maszyny nazewnictwo jest oczywiście dowolne. Ale dla człowieka już niekoniecznie. Skoro, jak sam napisałeś, uczysz się, warto chyba od razu uczyć się dobrych praktyk i wyrabiać nawyki. W rzeczywistym świecie nigdy (albo prawie nigdy) nie piszesz kodu, którego nikt inny potem nie zobaczy. A nawet w takim wypadku, sam będziesz się za pół roku zastanawiał "o co kaman w tym kodzie??" jeżeli wyrobisz sobie nawyki takie jak nazywanie klasy "Metody" (kolekcję obiektów nazwiesz "Obiekty"?). Naprawdę warto trzymać się ogólnie przyjętych konwencji.

0

Dzięki, poprawie kod żeby trzymać się przyjętych konwencji. Zależy mi na przejrzystości kodu i na jego minimalnej ilości.

0

Dobre nazwy ewidentnie poprawiają przejrzystość kodu. Jeśli byś nazwał tą klasę "Komunikacja" albo nawet "KomunikacjaSieciowa" to czytelność kodu automatycznie wzrasta.

0

Ok, co do nazw jak już pisałem, rozumiem mój błąd, racja - jak ktoś inny weźmie kiedyś mój kod to będzie miał problem, może nie zrozumieć i mnie "powiesi" :))

Wyjaśnij mi proszę jeszcze poniższą kwestię bo nie bardzo rozumiem :

MarekR22 napisał(a):

Przykładowo TcpClient powinien być polem klasy do komunikacji

0

Każda klasa powinna zamykać w hermetyczny sposób pewną minimalną funkcjonalność (tu komunikację sieciową) i wystawiać przez swoje API tylko to co niezbędne.
Jako, że każda twoja metoda w tej twojej klasie przyjmuje TcpClient i w zasadzie tylko te metody używają tego obiektu, logiczne się chyba staje, że to powinno być pole wewnątrz tej klasy (oczywiście klasa musi być uzupełniona o inne metody taka jak "polacz" "rozlacz" itp).

0

Czy tak będzie lepiej ??

 
class KomunikacjaSieciowa
    {
        public static TcpClient KlientTCP;
        public static string IP = Properties.Settings.Default.AdresIP;
        public static int nr_portu = Properties.Settings.Default.NrPortu;
        
        public static string OdczytDanychZWagi(byte[] WysylaneZapytanie)
        {
            // Wysyłka komunikatu do podłączonego serwera TCP
            NetworkStream stream = KlientTCP.GetStream();
            stream.Write(WysylaneZapytanie, 0, WysylaneZapytanie.Length);

            // Otrzymanie odpowiedzi

            // Buffor na odpowiedz
            byte[] odpowiedz = new Byte[256];

            // String do przechowywania odpowiedzi w ASCII
            String responseData = String.Empty;

            // Odczyt danych z serwera
            Int32 bytes = stream.Read(odpowiedz, 0, odpowiedz.Length);
            responseData = System.Text.Encoding.ASCII.GetString(odpowiedz, 0, bytes);
            return responseData;
        }

        public static void WysylkaDoWagi(byte[] KomunikatWysylany)
        {
            NetworkStream stream = KlientTCP.GetStream();
            stream.Write(KomunikatWysylany, 0, KomunikatWysylany.Length);
        }
    }

Co do połączenia - wywołuję je w zdarzeniu innej klasy (jeśli ustawiono autostart połączenia to w otwarciu Form1, jeśli nie to jest Button "Połącz") poprzez:

 
KomunikacjaSieciowa.KlientTCP = new TcpClient();
KomunikacjaSieciowa.KlientTCP.Connect(IPAddress.Parse(KomunikacjaSieciowa.IP), KomunikacjaSieciowa.nr_portu);

Nie zamykam połączenia gdyż program ma na celu cały czas komunikować się wagą i w zależności od otrzymywanych danych wykonywać różne działania.
Jakieś sugestie co do tej części?

0

jak patrze dokładniej co robisz to nie. Pomijając treść funkcji to powinno wyglądać tak (C# używałem krótko jakieś 3 lata temu, więc może być coś przekręcone, chodzi o samą filozofię):

class WagaSiciowa : public  IDisposable {
public WagaSiciowa(String adres);
public WagaSiciowa();

public void polacz(String adres);
public double OstatniPomiar();
public void Aktualizuj();
public void Taruj();
public boolean czyWagaGotowa();

public delegate void wagaJuzGotowa(boolean gotowa);
public delegate void dostepnyNowyPomar(double wartosc);

public overide void Dispose();

privte TcpClient socket;
}

W ten sposób zamykasz komunikację z wagą w klasie, która reprezentuje wagę. Całą resztę programu nie interesuje jak ta waga jest podpięta, przez sieć, port com lub USB.
Mało tego robiąc to w ten sposób bezproblemowo możesz potem poprawić kod by obsługiwał dwie wagi.

Jak popiszesz trochę większych programów to na pewno załapiesz o co chodzi.

PS. Mam nadzieje, że wiesz co to są delegaty w C#.
PS2. Implementacja interfejsu IDisposable jest w zasadzie obowiązkowa, jeśli wewnątrz klasy znajdują się pola klasy, które implementują ten interfejs.

0

Przeniosłem już również połączenie z wagą do klasy KomunikacjaSieciowa i "ubrałem" w metodę.
Dzięki za sugestie dzięki którym kod robi się coraz bardziej przejrzysty i łatwiejszy do edycji a program zyskuje nowe możliwości.
Co do obsługi drugiej wagi - domyślnie program ma obsługiwać kilka wag - wpierw chciałem jako początkujący zrobić dla jednej wagi i odpalić kilka programików, każdy z innymi ustawieniami w pliku settings.
Co do delegat - czytam, szukam ale jeszcze nie do końca "ogarniam" ale mam nadzieję że tak jak napisałeś -jak trochę "popiszę" to dojdę co i jak.
Teraz czas przejść do najtrudniejszego czyli poukładania kiedy co program ma robić gdyż nikt go nie będzie obsługiwał z poziomu Windows tylko ma on sam działać w zależności od zachowań wagi i tego co operator wybierze z klawiatury wagi.

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