Προς το περιεχόμενο
  • 0

Ερωτήσεις για C#


migf1

Ερώτηση

Ανοίγω αυτό το νήμα, ως αντίστοιχο του Ερωτήσεις για C για να έχουμε συγκεντρωμένα θέματα που αφορούν την C#.

 

Προέκυψε λοιπόν ανάγκη να μάθω C#, οπότε ξεκίνησα προχτές. Προς το παρόν αποσπασματικά από κάποια online tutorials για να πάρω μια γενική εικόνα, πριν καθίσω να διαβάσω κανονικό βιβλίο.

 

Φτιάχνω ένα απλό πρόγραμμα, προκειμένου να εξοικειωθώ με τη γλώσσα αρχικά σε κονσόλα, και ήδη έχω μαζέψει πολλές ερωτήσεις για τους έμπειρους στη γλώσσα.

 

Το πρόγραμμα ουσιαστικά υλοποιεί μια κλάση GreekName, για στοιχειώδη διαχείριση ελληνικών ονομάτων στην κονσόλα των Windows (CultureInfo.Name == "el-GR" ή/και "el").

 

Ρωτάει κι αποθηκεύει το όνομα ως string θεωρώντας το ονομαστική πτώση, και κατόπιν το αναπαράγει σε κλητική πτώση (διενεργώντας κάποια validation checks κατά την είσοδο).

 

Π.χ....

 

>
Το πλήρες όνομά σας; α
*** τα ονόματα πρέπει να περιέχουν τουλάχιστον 2 γράμματα

Το πλήρες όνομά σας; ΑλΈΚο2 ΑΘΑΝΑΣΙΟΥ
*** επιτρέπονται μόνο γράμματα

Το πλήρες όνομά σας; αΛΈκοΣ ΠΑπαΓΙάΝΝΗς
Γειά σου Αλέκο Παπαγιάννη.

 

Βέβαια το υλοποιώ πολύπλοκα, για να εξασκώ τα διάφορα που διαβάζω (π.χ. overloaded constructors/methods, public/private properties αυτόματες και μη, callback functions μέσω delegates, κλπ) κι έχω μαζέψει ήδη αρκετές ερωτήσεις αλλά θα ξεκινήσω με πολύ απλές για αρχή

 

Για αρχή, υπάρχει κάποια ουσιαστική διαφορά αν στην υλοποίηση των properties χρησιμοποιούμε ή όχι το this.

 

Για παράδειγμα, έχω ορίσει την property Text ως εξής...

 

>
public class GreekName
{
   // private fields
   private CultureInfo _ci;    // CultureInfo
   private string _text;        // the actual text
   private string _fname, _lname;

   /** @brief The simplest constructor of the class. */
   public GreekName()
   {
       this.Text = string.Empty;
       _ci = new CultureInfo("el-GR", false);
   }
   /** @brief Overload constructor, accepting text for the name. */
   public GreekName( string text )
   {
       this.Text = string.IsNullOrEmpty(text) ? string.Empty : text.Trim();
       _ci = new CultureInfo("el-GR", false);
   }
   /** @brief Overloaded constructor, accepting text and culture. */
   public GreekName( string text, string cultureName )
   {
       this.Text = new GreekName(text).Text;
       if ( string.IsNullOrEmpty(cultureName)
       || ("el-GR" != cultureName && "el" != cultureName )
       ){
           _ci = new CultureInfo("el-GR", false);
       }
       else {
           _ci = new CultureInfo(cultureName, false);
       }
   }
...
   /** @brief Property for getting/setting the name's text string. */
   public string Text
   {
       get { return this._text; }
       set { this._text = value.Trim(); }
   }
...

 

Κερδίζω/χάνω τίποτα αν την ορίσω χωρίς αναφορά στο this? ...

 

>
   /** @brief Property for getting/setting the name's text string. */
   public string Text
   {
       get { return _text; }
       set { _text = value.Trim(); }
   }

 

Επίσης, είναι καλή πρακτική να την χρησιμοποιώ στους constructors ή είναι καλύτερα να χρησιμοποιώ απευθείας το text filed; Κι αν ναι, με ή χωρίς this μπροστά;

 

EDIT:

 

Έβαλα και του υπόλοιπους constructors για να υπάρχει πιο σφαιρική εικόνα της υλοποίησής του (να μου πείτε αν έχω κάνει και καμια μαμακία).

Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • Απαντήσεις 51
  • Δημιουργία
  • Τελευταία απάντηση

Συχνή συμμετοχή στην ερώτηση

Συχνή συμμετοχή στην ερώτηση

Δημοφιλή Μηνύματα

Το ξερω οτι εισαι ξεροκεφαλος σε μερικα θεματα, αλλα θα στο πω. Βαλε vs ή κατι που να εχει intelliSense, αλλιως απλα παρατα τα.

Το νόημα του encapsulation δεν είναι να έχεις set/get για κάθε field. Αν ήταν έτσι προφανώς και θα οριζες τα fields σου public και θα ξεμπερδευες.   Το βασικό που πρέπει να καταλάβεις είναι πως θα

Πες οτι έχεις μια class A με μια static method Foo που έχει optional parameter int bar = 42 στην assembly a.dll.   Εσύ τώρα γράφεις κώδικα σε μια άλλη assembly b.exe (έχοντας κάνει reference την a.d

Δημοσιευμένες Εικόνες

Προτεινόμενες αναρτήσεις

  • 0

Το ξερω οτι εισαι ξεροκεφαλος σε μερικα θεματα, αλλα θα στο πω. Βαλε vs ή κατι που να εχει intelliSense, αλλιως απλα παρατα τα.

 

Εντάξει νομίζω είναι λίγο υπερβολικό να του ζητάς να τα παρατήσει διαφορετικά.

 

Κι εγώ το βρίσκω εντελώς χαμένο κόπο και εφιαλτικά αργό να γράφεις C# σε notepad++ οταν δίπλα σου κάθεται το vs και σκονίζεται και θα μπορούσα να επιχειρηματολογήσω ώρες στο γιατι το πιστεύω αλλά στην τελική ο κάθε ένας είναι ελεύθερος να κάνει ο,τι και όπως θέλει.

 

Ακόμα και αν αυτό που κάνει του αυξάνει τις πιθανότητες να πάρει εντελώς λειψή εικόνα της πλατφόρμας ή ακόμα να κουραστεί και να τα παρατήσει ενώ αντίθετα κάτι τέτοιο θα είχε αποφευχθεί.

  • Like 1
Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • 0

Εγώ πάλι ρε παιδιά δεν καταλαβαίνω γιατί δεν μπορείτε να αποδεχτείτε πως ο κάθε άνθρωπος έχει διαφορετικούς κώδικες και μεθοδολογίες.

 

Θα μάθω τα βασικά της γλώσσας σε Notepad++, και όταν αρχίσω να ασχολούμαι με πιο advanced πράγματα τότε θα πάω σε κανονικό IDE. Θα 'ναι το VS Express, το SharpDevelop, το MonoDevelop, δεν το ξέρω ακόμα (προς το παρόν δεν με απασχολεί καν αυτό το θέμα).

 

 

 

Παρεμπιπτόντως, μια χαρά auto-completion engine έχει και το Notepad++ ...

 

post-38307-0-34112600-1353013974_thumb.jpg

 

αλλά το μόνο από τα provided xml που είναι 100% πλήρες είναι για την php και ακολουθούν C και C++ που περιέχουν τις περισσότερες από τις στάνταρ συναρτήσεις (ειδικά η C που έχει και λιγότερες).

 

Για C# δεν έχει ούτε μια συνάρτηση (την String.Split() και τα overlaod της εικόνας, τα έφτιαξα πρόχειρα εγώ) και δεν βρήκα να έχει φτιάξει κανείς (όπως π.χ. έχουν φτιάξει για lua, python, ακόμα και για Unity3d)

 

 

 

 

Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • 0
Είμαι λίγο αναποφάσιστος για το αν θα πρέπει να ακολουθήσω τα στάνταρ της Microsoft ή του Mono. Βασικά είναι πολύ μεγάλη η ασυμβατότητα μεταξύ των runtimes τους (αν υπάρχει μεγάλος βαθμός συμβατότητας/portability μάλλον θα προτιμήσω να διαβάσω του Mono).

 

Περι ορέξεως... και μένα δε μου αρέσουν (και δεν ακολουθώ σε προσωπικό μου κώδικα) μερικά από τα guidelines της Microsoft (πχ braces on their own line σε ένα if της μίας γραμμής το θεωρώ υπερβολή), αλλά σαν σύνολο τις θεωρώ πολύ προτιμότερες από του Mono.

 

Την ασυμβατότητα μεταξύ των runtimes δε θα την έλεγα μεγάλη. Φυσικά τα τελευταία features πάντα έπονται του .NET αλλά overall δεν είναι κι άσχημα.

 

Επίσης, με την ευκαιρία που διάβασα τη σελίδα του Mono, βρίσκω την ευκαιρία να επισημάνω το εξής με το οποίο συμφωνώ παραπάνω από απόλυτα:

 

Performance and Readability

 

It is more important to be correct than to be fast.

It is more important to be maintainable than to be fast.

Fast code that is difficult to maintain is likely going to be looked down upon.

 

Αμήν.

 

Δεν ξέρω αν το πήρε το μάτι σου στις προηγούμενες σελίδες, που κάπου το ανέφερα, το σκεπτικό μου για αυτού του είδους την υλοποίηση των setters ήταν για να αποφορτίσω τους getters από τα συνεχόμενα calculations, μιας και οι getters χρησιμοποιούνται πολύ συχνότερα.

 

Αντιτίθεται αυτό το σκεπτικό με την κοινή πρακτική στη γλώσσα; Θεωρείται κακή πρακτική;

 

Εν συντομία, δύο λέξεις: "premature optimization"?

 

Γράφεις ένα πρόγραμμα της πλάκας που το χρησιμοποιείς για να μάθεις τα features της γλώσσας: το θεωρώ αστείο να μιλάμε για το performance των getters.

 

Γράφεις ένα σοβαρό εμπορικό πρόγραμμα στο οποίο οι getters αυτοί δεν χρησιμοποιούνται μέσα σε inner loop σε κάποιο CPU-bound τμήμα του προγράμματος: το θεωρώ λάθος και misguided να μιλάμε για το performance των getters.

 

Και πάμε άλλη μια φορά για εμπέδωση:

 

It is more important to be correct than to be fast.

It is more important to be maintainable than to be fast.

Fast code that is difficult to maintain is likely going to be looked down upon.

 

Τώρα, that said, δεν είναι κακή πρακτική από μόνο του το να κάνεις το calculation στον setter -- και γω αυτό έκανα στον κώδικα που είχα δώσει νωρίτερα. Κακή πρακτική είναι να το κάνεις αυτό εις βάρος της αναγνωσιμότητας του κώδικα.

 

Ή με άλλα λόγια: συμφωνώ με την ορθότητα της απόφασής σου, αλλά διαφωνώ (πολύ) με τον τρόπο που έφτασες σ' αυτή.

 

 

Μια ερώτηση: Κερδίζει κάτι κάποιος αν κάνει trivially implemented properties με private μεταβλητές αντί να κάνεις τις μεταβλητές public?

 

Μιλάω βέβαια μόνο για τέτοιο trivial implementation. Με την εξης λογική: Γιατί να μην κάνει απλά τη μεταβλητή public, και μετά αν αποφασίσει ότι θέλει να έχει πιο πολύ πολύπλοκη λογική να την κάνει property με το ίδιο όνομα. Έτσι ο κώδικας στις client classes δεν κάνει break.

 

Θα ξεκινήσω από το τέλος: κι όμως, ο κώδικας στις client classes θα κάνει break και μάλιστα με πολλούς τρόπους. Θα ήταν σωστότερο να πεις "αν κάνεις recompile τα sources των client classes, δε θα φας compilation error", αλλά και πάλι όχι 100% σωστό.

 

Βάλατε LinqPad που είπα παραπάνω? Ας δούμε αυτό το απλό πρόγραμμα:

 

>void Main()
{
var f = new Foo();
f.A = "hello";
f.B = "hello";
}

class Foo {
public string A { get; set; }
public string B;
}

 

Πατάμε κάτω στο output window εκεί που λέει "IL" και βλέπουμε την CIL που βγάζει ο compiler γι' αυτό τον κώδικα:

 

>
IL_0001: newobj	 UserQuery+Foo..ctor
IL_0006: stloc.0	
IL_0007: ldloc.0	
IL_0008: ldstr	 "hello"
IL_000D: callvirt UserQuery+Foo.set_A
IL_0012: nop		
IL_0013: ldloc.0	
IL_0014: ldstr	 "hello"
IL_0019: stfld	 UserQuery+Foo.B

 

 

Τι σημαίνουν αυτά τα instructions (δεν είναι απαραίτητο όμως για τη συνέχεια του post μου):

 

 

Οι stloc και ldloc (store/load αντίστοιχα) μεταφέρουν τιμές προς/από local variables (δηλαδή στο stack της process που τρέχει) στο ιδεατό stack της virtual machine του runtime. Οπότε, η newobj κάνει create ένα object και το βάζει στο CLR stack. H stloc.0 κάνει pop τον pointer σ' αυτό το object και τον γράφει στη local μεταβλητή f. Οι επόμενες 2 ld φορτώνουν τα ορίσματα για την callvirt που ακολουθεί, η οποία καλεί τον setter της property. Στο τέλος η αποθήκευση σε field γίνεται παρομοίως με την stfld.

 

 

 

Όπως είναι φανερό (αλλά και κατανοητό αν σκεφτεί κανείς ότι οι properties στην ουσία είναι methods), τελείως άλλο instruction χρησιμοποιείται στη μία περίπτωση και τελείως άλλο στην άλλη. Επομένως αν δεν κάνεις recompile τον client κώδικα και απλά πετάξεις τη νέα σου dll επάνω θα έχουμε πυροτεχνήματα.

 

Επιπλέον, τι γίνεται με τον κώδικα που κάνει reflection?

 

Ας πούμε π.χ. με το παραπάνω object f:

 

>Console.WriteLine(f.GetType().GetProperty("A").GetValue(f, null));

 

Αν αλλάξεις το property σε field (ή το αντίθετο αν έκανα reflect πάνω στο field) αυτός ο κώδικας απλά θα σκάσει με NullReferenceException at runtime. Θα το χαρακτήριζα λοιπόν με άνεση breaking change.

 

Τέλος υπάρχουν και άλλες πιο ψαγμένες ασυμβατότητες -- π.χ. μπορείς να κάνεις ref σε fields, αλλά όχι σε properties.

 

Τώρα, όσον αφορά το "τι να χρησιμοποιώ λοιπόν και με ποιό κριτήριο", τα έχει ήδη πει ο Jon Skeet οπότε πάω πάσο. Το ζουμί είναι στην ενότητα "The philosophical reason for only exposing properties".

 

Απαντήσεις σε μετέπειτα posts αργότερα, ήδη μάκρυνε πολύ αυτό το σεντόνι.

  • Like 1
Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • 0

Το σεντονάκι που χρωστούσα...

 

Thanks και για τον κώδικα! Κάτι παρόμοιο με τη χρήση του LINQ έχω βάλει ήδη στη input validation method, που απαιτεί μονάχα γράμματα ή blanks... αλλά βασικά κάπου την βρήκα σχεδόν έτοιμη, ψάχνοντας για κάτι άλλο. Οπότε την έβαλα παπαγαλίστικα, μέχρι να φτάσω να διαβάσω για το LINQ (ομοίως και για τα Rexeges... δεν έχω φτάσει ακόμα, τα σημείωσα όμως για να τα ξαναδώ όταν θα είμαι σε θέση να καταλαβαίνω και τα mechanics τους).

 

FYI ο κώδικας που παραθέτεις στην κλίμακα 1-10 παίρνει μετα βίας το 3 -- έχει μια ολόκληρη σειρά από χοντρά προβλήματα σχεδιασμού. Τελείως ενδεικτικά αναφέρω:

  1. Γενικά είναι κώδικας C γραμμένος με σύνταξη C#
  2. Έχει κατουρήσει στον τάφο της έννοιας του separation of concerns -- η ίδια method κάνει αποδοχή εισόδου, validation και επιστροφή τελικού αποτελέσματος
  3. To validation γίνεται με πολύ άσχημο τρόπο (ειδικά η επιλογή του error message...)
  4. Κάνει modify το this (γιατί? με ποιά λογική να μην είναι static και να επιστρέφει ένα καινούριο instance?) αλλά... το επιστρέφει κιόλας (εκτός συγκεκριμένων περιπτώσεων αυτό είναι τεράστιο red flag)

Πάντως και οι 2 κώδικες που μου έδωσες, έχουν το πρόβλημα πως αν υπάρχουν κολλητά blanks ανάμεσα στα tokens, τότε προστίθενται ως κενά. Πριν λίγο ανακάλυψα μια overloaded έκδοση της split η οποία δέχεται ως 2ο όρισμα ένα "StringSplitOptions", για το αν θα κρατάει ή όχι blank tokens.

 

Και υποθέτω και αρκετά ακόμα προβλήματα τα οποία δεν ανακαλύψαμε γιατί κανείς δεν κάθησε να το αναλύσει. Τον κώδικα τον πήρα ξεκινώντας απ' αυτό που έδωσες και συνέχισα απο κει, και μάλιστα ανέφερα πως τα προβλήματα που εντοπίζω είναι "για παράδειγμα".

 

Αν πάντως είχες Intellisense το overload με StringSplitOptions δε θα χρειαζόταν να το ανακαλύψεις.

 

Διορθώνεται με casting: .Split( (char[])null, StringSplitOptions.RemoveEmptyEntries );

 

είναι όμως safe?

 

Το πρόβλημα είναι πως το null είναι αποδεκτή τιμή για οποιοδήποτε reference type, επομένως το null δεν "είναι" τύπου string περισσότερο απ' οτι είναι τύπου Dictionary<Foo, Bar> ή τύπου WhateverCustomClass. O compiler σου λέει πως δεν μπορεί να καταλάβει ποιό από τα 2 overloads θέλεις να καλέσεις. Κάνοντας cast το null του δίνεις να καταλάβει και το θέμα τελειώνει εκεί. Με ποιό τρόπο θα μπορούσε να μην είναι safe?

 

Τώρα το αν η method που θα καλέσεις τελικά μόλις δει null αποφασίσει να σου κάνει format το δίσκο δεν είναι πρόβλημα του compiler.

 

Εννοείς πως με τα regex δεν χρειάζεται να δηλώσεις explicitly ποιοι χαρακτήρες θα λογιστούν ως token separators?

 

Δηλώνω explicitly: o separator είναι οποιοδήποτε word boundary (http://www.regular-expressions.info/wordboundaries.html).

 

 

Μιας που μιλάμε για regular expressions... είναι "kind of important" όταν γράφεις software.

 

 

 

ΔΕΝ ΥΠΑΡΧΕΙ ΚΑΝΕΝΑΣ ΣΤΟ ΠΡΟΣΩΠΙΚΟ ΤΟΥ INSOMNIA ΠΟΥ ΝΑ ΕΝΔΙΑΦΕΡΕΤΑΙ ΚΑΙ ΝΑ ΜΠΟΡΕΙ ΝΑ ΚΑΝΕΙ ΚΑΤΙ ΓΙΑ ΤΟ ΓΕΓΟΝΟΣ ΟΤΙ Ο EDITOR ΕΙΝΑΙ ΤΟΣΟ ΑΘΛΙΟΣ;;;

 

 

Εγώ πάλι ρε παιδιά δεν καταλαβαίνω γιατί δεν μπορείτε να αποδεχτείτε πως ο κάθε άνθρωπος έχει διαφορετικούς κώδικες και μεθοδολογίες.

 

Αυτό μπορούμε να το αποδεχτούμε. Εκείνο που μας δυσκολεύει είναι το να δείχνεις σε κάποιον το copy/paste κι αυτός να σου λέει ότι μια χαρά την κάνει τη δουλειά πληκτρολογώντας το ίδιο κείμενο manually πολλές φορές.

 

Η μεθοδολογία που επιλέγεις είναι αντικειμενικά αντιπαραγωγική και (συζητίσιμο, αλλά κατά την άποψή μου επίσης αντικειμενικό) δεν έχει να προσφέρει τίποτα πέραν του ότι το N++ είναι ένα γνώριμο εργαλείο ενώ με το VS βγαίνεις εκτός comfort zone. Αν απλά το θέμα ήταν να δεις τι γίνεται under the hood όταν πατάς compile, το VS έχει ειδικό output window όπου με τις κατάλληλες ρυθμίσεις φαίνεται ακριβώς το τι συμβαίνει. Σε προηγούμενο post είχα δώσει και link για όλα τα options του compiler (csc). Για τους λόγους αυτούς λοιπόν, αντικειμενικό και το ότι το N++ δεν έχει να προσφέρει τίποτα.

 

Σταματάω εδώ για να μην διαψέυσω τον εαυτό μου σχετικά με το ότι μπορούμε να το αποδεχτούμε. :P

Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • 0

...

FYI ο κώδικας που παραθέτεις στην κλίμακα 1-10 παίρνει μετα βίας το 3 -- έχει μια ολόκληρη σειρά από χοντρά προβλήματα σχεδιασμού. Τελείως ενδεικτικά αναφέρω:

  1. Γενικά είναι κώδικας C γραμμένος με σύνταξη C#
  2. Έχει κατουρήσει στον τάφο της έννοιας του separation of concerns -- η ίδια method κάνει αποδοχή εισόδου, validation και επιστροφή τελικού αποτελέσματος
  3. To validation γίνεται με πολύ άσχημο τρόπο (ειδικά η επιλογή του error message...)
  4. Κάνει modify το this (γιατί? με ποιά λογική να μην είναι static και να επιστρέφει ένα καινούριο instance?) αλλά... το επιστρέφει κιόλας (εκτός συγκεκριμένων περιπτώσεων αυτό είναι τεράστιο red flag)

 

Δεκτές οι παρατηρήσεις, αν και θα προτιμούσα να συνοδεύονταν με κώδικα που θα έκανε demonstrate την καλή πρακτική (btw, την συνάρτηση την έκανα συνειδητά να κάνει πολλές δουλειές, θα αυτονομήσω τμήματά της όταν προσθέσω διαχείριση command-line argumets).

 

Το πρόβλημα είναι πως το null είναι αποδεκτή τιμή για οποιοδήποτε reference type, επομένως το null δεν "είναι" τύπου string περισσότερο απ' οτι είναι τύπου Dictionary<Foo, Bar> ή τύπου WhateverCustomClass. O compiler σου λέει πως δεν μπορεί να καταλάβει ποιό από τα 2 overloads θέλεις να καλέσεις. Κάνοντας cast το null του δίνεις να καταλάβει και το θέμα τελειώνει εκεί. Με ποιό τρόπο θα μπορούσε να μην είναι safe?

 

Οπότε αποτελεί ή όχι πρόβλημα (στην αρχή το χαρακτηρίζεις ως "πρόβλημα" αλλά στο τέλος ως "safe"); Αν αποτελεί πρόβλημα, ποιος κώδικας θεωρείται good practice σε αυτή την περίπτωση;

 

Δηλώνω explicitly: o separator είναι οποιοδήποτε word boundary (http://www.regular-exp<b></b>ressions.info/wordboundaries.html).

 

 

Μιας που μιλάμε για regular exp<b></b>ressions... είναι "kind of important" όταν γράφεις software.

 

 

Προσωπικά μου έχουν χρειαστεί ελάχιστες φορές.

 

Αυτό μπορούμε να το αποδεχτούμε. Εκείνο που μας δυσκολεύει είναι το να δείχνεις σε κάποιον το copy/paste κι αυτός να σου λέει ότι μια χαρά την κάνει τη δουλειά πληκτρολογώντας το ίδιο κείμενο manually πολλές φορές.

 

Η μεθοδολογία που επιλέγεις είναι αντικειμενικά αντιπαραγωγική και (συζητίσιμο, αλλά κατά την άποψή μου επίσης αντικειμενικό) δεν έχει να προσφέρει τίποτα πέραν του ότι το N++ είναι ένα γνώριμο εργαλείο ενώ με το VS βγαίνεις εκτός comfort zone.

 

Δεν βρίσκομαι σε στάδιο παραγωγικότητας αλλά εκμάθησης. Προτιμώ να δυσκολευτώ στην αρχή αλλά να πάρω βάσεις που θα μου εντυπωθούν, παρά να χαίρομαι με το IDE μου κρύβει τα mechanics για να μου δημιουργήσει αίσθηση "παραγωγικότητας" αλλά όταν χρειαστεί να αλλάξω περιβάλλον να χάσω τα αυγά και τα πασχάλια.

 

Αν απλά το θέμα ήταν να δεις τι γίνεται under the hood όταν πατάς compile, το VS έχει ειδικό output window όπου με τις κατάλληλες ρυθμίσεις φαίνεται ακριβώς το τι συμβαίνει. Σε προηγούμενο post είχα δώσει και link για όλα τα options του compiler (csc). Για τους λόγους αυτούς λοιπόν, αντικειμενικό και το ότι το N++ δεν έχει να προσφέρει τίποτα.

 

Σταματάω εδώ για να μην διαψέυσω τον εαυτό μου σχετικά με το ότι μπορούμε να το αποδεχτούμε. :P

 

Tο "csc /?" μια χαρά με εξυπηρετεί προς το παρόν. Ομοίως και το Notepad++.

 

Παρεμπιπτόντως, για να τελειώνουμε με αυτή την ιστορία (αυτό πάει και στον "μη ξεροκέφαλο" παπι)), να σας δώσω κι ένα παραπάνω κίνητρο για να μπορέσετε να το αποδεχτείτε όσο το δυνατόν πιο ανώδυνα... ο Herbert Schildt όχι μόνο δείχνει να μην έχει πρόβλημα με την προσέγγισή μου, αλλά την ενθαρρύνει κιόλας...

 

C#4.0 - The Complete Reference - Page #14

 

Using csc.exe, the C# Command-Line Compiler

 

Although the Visual Studio IDE is what you will probably be using for your commercial

projects, some readers will find the C# command-line compiler more convenient, especially

for compiling and running the sample programs shown in this book. The reason is that you

don’t have to create a project for the program. You can simply create the program and

then compile it and run it—all from the command line. Therefore, if you know how to use

the Command Prompt window and its command-line interface, using the command-line

compiler will be faster and easier than using the IDE.

 

Οπότε να προσθέσω κι εγώ (επειδή μου τα έχετε κάνει τσουρέκια με αυτό το θέμα): if you don't know how to use the Command Prompt window and its command-line interface, it's never too late :P

Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • 0
Δεκτές οι παρατηρήσεις, αν και θα προτιμούσα να συνοδεύονταν με κώδικα που θα έκανε demonstrate την καλή πρακτική

 

Και γω αυτό σκέφτηκα να κάνω αρχικά, αλλά μετά συνειδητοποίησα ότι λείπουν κάποια κομμάτια του παζλ οπότε άλλαξα γνώμη. Τέλος πάντων, ας πούμε κάπως έτσι:

 

>class GreekName {
   public string Text { get; set; }

   public bool Validate()
   {
       return this.GetValidationerror() == null;
   }

   public string GetValidationerror()
   {
       if (string.IsNullOrEmpty(this.Text))
       {
           return "The name cannot be blank.";
       }

       if (this.Text.Length < 2)
       {
           return "Name too short.";
       }

       if (!this.Text.All(c => char.IsLetter(c) || char.IsWhiteSpace(c)))
       {
           return "Only letters allowed.";
       }

       return null;
   }
}

 

 

και μετά κάπου εκτός της class:

 

>private static GreekName ReadNameFromConsole(string prompt, bool verbose)
{
   var greekName = new GreekName();

   while (!greekName.Validate())
   {
       if (greekName.Text != null && verbose)
       {
           Console.WriteLine(greekName.GetValidationerror());
       }
       if (prompt != null)
       {
           Console.Write(prompt);
       }
       greekName.Text = (Console.ReadLine() ?? string.Empty).Trim();
   }

   return greekName;
}

 

 

(btw, την συνάρτηση την έκανα συνειδητά να κάνει πολλές δουλειές, θα αυτονομήσω τμήματά της όταν προσθέσω διαχείριση command-line argumets).

 

Γιατί όμως να κάνεις κάτι που ξέρεις ότι είναι 100% λάθος αν μπορείς να κάνεις κάτι που είναι λιγότερο λάθος; (ακόμα κι αν δεν έχεις ακόμα αρκετά δεδομένα για να αποφασίσεις τι είναι "σωστό")

 

Οπότε αποτελεί ή όχι πρόβλημα (στην αρχή το χαρακτηρίζεις ως "πρόβλημα" αλλά στο τέλος ως "safe"); Αν αποτελεί πρόβλημα, ποιος κώδικας θεωρείται good practice σε αυτή την περίπτωση;

 

Πρόβλημα = compiler error. Κάνεις cast και problem solved. Δεν έχει κάτι περισσότερο το συγκεκριμένο θέμα.

 

Προσωπικά μου έχουν χρειαστεί ελάχιστες φορές.

 

Εμένα πάλι δε μου έχει χρειαστεί ιδιαίτερα η fgets. Βάζω fgetc μέσα σ' ένα loop και καθάρισα. ;)

 

Τέλος όσον αφορά τα περι N++, command line και Schildt: εγώ πάλι έχω ένα project στο VS που όποτε θέλω να γράψω κάτι non-trivial μεν αλλά για πέταμα δε, απλά σβήνω όλα τα περιεχόμενα του Whatever.cs (CTRL+A, DEL), γράφω ο,τι είναι να γράψω, CTRL+TAB γράφω στο Program.cs στη Main ο,τι χρειάζεται, CTRL+F5 και τέλος. Καθ' όλη τη διάρκεια απολαμβάνω IntelliSense και R#. Δεν είμαι σίγουρος με ποιό τρόπο είναι faster το να τα κάνεις από command line αλλά ας μη το συζητήσουμε περισσότερο.

 

Τώρα το να λες ότι επειδή κάποιος χρησιμοποιεί VS δεν ξέρει να κάνει τα ίδια κι απο command line είναι σα να λες ότι επειδή πάει στη δουλειά με το αμάξι δεν ξέρει να κάνει ποδήλατο.

Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • 0

 

 

Και γω αυτό σκέφτηκα να κάνω αρχικά, αλλά μετά συνειδητοποίησα ότι λείπουν κάποια κομμάτια του παζλ οπότε άλλαξα γνώμη. Τέλος πάντων, ας πούμε κάπως έτσι:

 

 

 

>class GreekName {
   public string Text { get; set; }

   public bool Validate()
   {
       return this.GetValidationerror() == null;
   }

   public string GetValidationerror()
   {
       if (string.IsNullOrEmpty(this.Text))
       {
           return "The name cannot be blank.";
       }

       if (this.Text.Length < 2)
       {
           return "Name too short.";
       }

       if (!this.Text.All(c => char.IsLetter(c) || char.IsWhiteSpace(c)))
       {
           return "Only letters allowed.";
       }

       return null;
   }
}

 

 

και μετά κάπου εκτός της class:

 

>private static GreekName ReadNameFromConsole(string prompt, bool verbose)
{
   var greekName = new GreekName();

   while (!greekName.Validate())
   {
       if (greekName.Text != null && verbose)
       {
           Console.WriteLine(greekName.GetValidationerror());
       }
       if (prompt != null)
       {
           Console.Write(prompt);
       }
       greekName.Text = (Console.ReadLine() ?? string.Empty).Trim();
   }

   return greekName;
}

 

 

 

Thanks για τον κώδικα. Έχω κι εγώ σκοπό να αυτονομήσω το validation, όταν θα κάνω το πρόγραμμα να δέχεται το input και ως command-line-arguments, οπότε θα χρειαστούν κι άλλες τροποποιήσεις.

 

Btw, το σκεπτικό των error-messages σε πίνακα είναι για να μπουν κάποια στιγμή ως hash-table ή όποια άλλη δομή μου παρέχει η γλώσσα (όταν δω τι τρόπους μου παρέχει) και να τυπώνω με hashing σε όποιες ρουτίνες τα χρειαστώ. Έτσι αφενός αν θέλω να τροποποιήσω ένα message θα το κάνω edit σε ένα μέρος, κι αφετέρου θα μπορώ να έχω πολύγλωσσα version.

 

Προφανώς η επιλογή αυτή της υλοποίησης είναι αποτέλεσμα του C background μου καθώς και της μη επαρκούς ακόμα γνώσης της C#

 

Γιατί όμως να κάνεις κάτι που ξέρεις ότι είναι 100% λάθος αν μπορείς να κάνεις κάτι που είναι λιγότερο λάθος; (ακόμα κι αν δεν έχεις ακόμα αρκετά δεδομένα για να αποφασίσεις τι είναι "σωστό")

 

Επειδή γράφω κώδικα μαθαίνοντας την γλώσσα, οπότε δεν είμαι σε θέση να γνωρίζω εκ των προτέρων αν, ποιες και πόσες αλλαγές θα χρειαστεί να ξανακάνω. Οπότε τα γράφω όπως μου έρχεται για να δω αν κάνουν τη δουλειά που θέλω εκείνη την ώρα, με όσο "prediction" μου επιτρέπουν οι λιγοστές μου ακόμα γνώσεις στην C#.

 

Εμένα πάλι δε μου έχει χρειαστεί ιδιαίτερα η fgets. Βάζω fgetc μέσα σ' ένα loop και καθάρισα. ;)

 

Δεν το έπιασα για να είμαι ειλικρινής.

 

Τέλος όσον αφορά τα περι N++, command line και Schildt: εγώ πάλι έχω ένα project στο VS που όποτε θέλω να γράψω κάτι non-trivial μεν αλλά για πέταμα δε, απλά σβήνω όλα τα περιεχόμενα του Whatever.cs (CTRL+A, DEL), γράφω ο,τι είναι να γράψω, CTRL+TAB γράφω στο Program.cs στη Main ο,τι χρειάζεται, CTRL+F5 και τέλος. Καθ' όλη τη διάρκεια απολαμβάνω IntelliSense και R#. Δεν είμαι σίγουρος με ποιό τρόπο είναι faster το να τα κάνεις από command line αλλά ας μη το συζητήσουμε περισσότερο.

 

Όταν θες να σώζεις το κάθε πρόγραμμα ξεχωριστά τι κάνεις; Υποθέτεις πως γράφω κώδικα τον τρέχω και τον σβήνω για να γράψω τον επόμενο; Αν ναι, δεν υποθέτεις σωστά

 

Άλλο παράδειγμα, με το Notepad++ έχω ανοιχτά 2 .cs αρχεία: MyExtras.cs και Test.c με το 1ο βγάζει dll και το άλλο βγάζει .exe χρησιμοποιώντας κλάσεις του dll.

 

Μόλις θέλω να προσθαφαιρέσω μια κλάση στο MyExtras.cs την γράφω, πατάω F6->CS DLL και μου ανανεώνει το .dll. Στο καπάκι την καλώ στον κώδικα του Test.cs, πατάω F6->CS EXE και μου παράγει και μου τρέχει το Test.exe χρησιμοποιώντας την ανανεωμένη .dll

 

Στο VS (ή σε όποιο άλλο IDE) δεν ξέρω πως γίνεται κάτι τέτοιο, και όπως έγραψα και πριν στην παρούσα φάση δεν με ενδιαφέρει να μάθω κάποιο συγκεκριμένο IDE αλλά τα basic mechanics της γλώσσας.

 

Τώρα το να λες ότι επειδή κάποιος χρησιμοποιεί VS δεν ξέρει να κάνει τα ίδια κι απο command line είναι σα να λες ότι επειδή πάει στη δουλειά με το αμάξι δεν ξέρει να κάνει ποδήλατο.

 

Δεν είπα πως "δεν ξέρετε", είπα "αν δεν ξέρετε".

Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • 0

Γεια σας, ασχολούμαι με την C# και έχω κάποιες ερωτήσεις - απορίες. Μαθαίνω τη γλώσσα από εδώ: http://www.tutorialspoint.com/csharp/  είναι καλή σελίδα ? Ποια προτείνετε εσείς ?

 

Έχω προχωρήσει πολύ μακριά αλλά εδώ --> C# - Encapsulation έχω μια απορία, την ενθυλάκωση γιατί πρέπει να την χρησιμοποιούμε ?

 

Δηλ τι να κρύψω - προστατεύσω ?

 

Ευχαριστώ εκ των προτέρων

Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • 0

Τα access specifiers χρησιμοποιούνται για να ορίσουν την "ορατότητα" των μεταβλητών έξω από την κλάσση. Αυτό στην αρχή φαίνεται να μην έχει νόημα αλλά είναι πολύ χρήσιμο όταν συνεργάζεσαι με άλλους αλλά και να αποτρέψει τον εαυτό σου να "κόψει δρόμο" σε κάτι γιατί είναι πιο εύκολο!.

 

ΠΧ: Συνήθως λέμε ότι οι μεταβλητές πρέπει να είναι private και όποιος θέλει να έχει δικαίωμα πρόσβασης θα πρέπει να περάσει από get-set μεθόδους.

 

Σκέφτεσαι: "μία μεταβλητή που απλά την χρησιμοποιώ χωρίς τπτ άλλο γιατί να την βάλω σε συνάρτηση;". Αργότερα μπορεί να μην την χρησιμοποιείς πια απλά αλλά να θέλεις να κάνεις και κάποιον έλεγχο. Θα ψάχνεις όλα τα σημεία που χρησιμοποιείται για να τα αλλάξεις;

 

Έστω ότι έχεις συνάρτηση (γιατί κάνεις ελέγχους) αλλά την έχεις αφήσει public και την μεταβλητή. Κάποια στιγμή επειδή θέλεις να κάνεις κάτι και οι έλεγχοι σε δυσκολεύουν σκέφτεσαι "έλα μωρέ, θα πάρω κατευθείαν την μεταβλητή, αφού είναι public!". Και κάπου εκεί αρχίζει το μπάχαλο στον κώδικα και τα bug που δεν ξέρεις γιατί υπάρχουν αφού έχεις έλεγχο στη συνάρτηση!

 

 

Οπότε στην ουσία "κρύβεις" τις μεταβλητές που δεν θέλεις να μπορούν να δουν οι "άλλοι" έξω από την κλάσση αλλά και προστατεύεις τις μεταβλητές σου ώστε να μην μπορέσει κάποιος να τις τροποποιήσει πέρα από τον προκαθορισμένο τρόπο που ορίζεις όταν φτιάχνεις την κλάσση.

  • Like 1
Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • 0

Ενα κλασσικο παραδειγμα ειναι η κλαση Date. Δεν θα ηθελες η ωρα να παρει τρελες τιμες(>23), ετσι δεν ειναι;

Εσυ ως σχεδιαστης μπορει να μην την χρησιμοποιησεις με λαθος τροπο αλλα σε ενα μεγαλο project ειναι πολυ πιθανο. Πραγμα το οποιο αποτρεπεται με τις καταλληλες setter μεθοδους. Οπως επισης μπορει να το κανει ο partner σου αν δεν εχεις δηλωσει καταλληλα pre/post - conditions.

 

Συνηθως τις ορατες μεταβλητες τις δηλωνουμε ως static final μιας και ειναι ανεξαρτητες κι ακινδυνες. Π.χ Math.pi.

 

Αλλος λογος ειναι η ασφαλεια. Ενας κακοβουλος χρηστης αν ξερει τι επικινδυνο κι ακαλυπτο στοιχειο περιεχει μια κλαση μπορει να το εκμεταλλευτει προς συμφερον του. Για αυτην την δουλεια ειναι ιδιαιτερα χρησιμα τα Reflections.

 

Επισης το encapsulation χρησιμοποιειται και για μεθοδους. Π.χ μια μεθοδος καλει μια βοηθητικη συναρτηση ενω η δευτερη -η καλουμενη- δεν προσφερει κατι στον προγραμματιστη.

  • Like 1
Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • 0

Από ποιους να τα κρύψω? Από τους άλλους προγραμματιστές - χρήστες ? Ναι, αλλά τότε σαν τους περιορίζω να χρησιμοποιήσουν τις δικές μου μεταβλητές και μεθόδους, όπως και στις βιβλιοθήκες που φτιάχνουν οι προγραμματιστές.


Άρα τα χρησιμοποιούμε για περισσότερη ασφάλεια, από του άλλους.

Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • 0

Τον ορισμό της ενθυλάκωσης το έχω καταλάβει, αλλά στον τρόπο λειτουργίας της μπερδεύομαι. Ας πούμε ότι έχω δύο κλάσεις και έχω βάλει private μεταβλητές και public μεθόδους και την main, τώρα ο άλλος προγραμματιστής πως θα διαβάσει αυτές κλάσεις, δηλ εγώ τη πρέπει να του δώσω, όλο τον κώδικά ή μόνο το όνομα του αντικειμένου που δημιούργησα ?

Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • 0

Για σενα ειναι οχι για αλλους. Αν θες μια μεταβληγη ή μεθοδος να μην μπορεις να την καλεσεις απο το ινστανς, τοτε την κανεις private. Το γιατι δεν θες να την καλεσεις απο αλλου, ειναι αλλο θεμα που θα το καταλαβεις πιο μετα. Για την ωρα να ξερειε πωσ εαν καλεσεις μεθοδο απο το ινστανς και αυτη ειναι private, tote exeis error.

  • Like 1
Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Εγγραφείτε για έναν νέο λογαριασμό

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα

  • Δημιουργία νέου...

Με την περιήγησή σας στο insomnia.gr, αποδέχεστε τη χρήση cookies που ενισχύουν σημαντικά την εμπειρία χρήσης.