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

Ερωτήσεις για 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
  • Δημ.
  • Τελ. απάντηση

Συχνή συμμετοχή στο θέμα

Τα properties θα τα χρησιμοποιούσα και στους constructors όπως σωστά κάνεις γιατί ειδικά σε πιο πολύπλοκα properties θα έχεις code duplication στον constructor. To property είναι στην ουσία το interface και έτσι είναι λογικό να γίνεται η προσπέλαση στην μεταβλητές.

Προσωπικά, όπου μπορούσα θα απέφευγα το function overloading και θα χρησιμοποιoύσα optional arguments. Απλότητα και αποφεύγεται code duplication που όπως βλέπεις έχεις αναπόφευκτα πχ στον constructor. DRY δλδ βασικά.

Όσο για το this, εγώ είμαι της λογικής της Python. Explicit is better than implicit (να βάζεις this δλδ). Φαίνεται δηλαδή κατευθείαν με το μάτι σε αυτόν που το διαβάζει ότι μιλάμε για instance variable. Λίγο παραπάνω verbosity για πολύ παραπάνω readability I will take any day any time :D

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Για να αποφύγεις τις επαναλήψεις κώδικα στους constructors χρησιμοποίησε το Constructor Chaining:

>
public GreekName() : this(string.Empty, "el-GR") {}

public GreekName( string text ) : this( text, "el-GR" ){}

public GreekName( string text, string cultureName )
{
   this.Text = string.IsNullOrEmpty(text) ? string.Empty : text; //Edo den xreiazetai Trim() giati ginetai sto property
   if ( string.IsNullOrEmpty(cultureName) || ("el-GR" != cultureName && "el" != cultureName ) )
   {
    _ci = new CultureInfo("el-GR", false);
   }
   else
   {
       _ci = new CultureInfo(cultureName, false);
   }
}

Ή αλλιώς μέσω του optional arguments, που είπε και o iceblade, βάζεις default τιμές στον constructor και μετά θέτεις όποια θέλεις κατά την κλήση.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

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

 

 

Αν γράψεις αυτό θα βγάλει ArgumentNullException επειδή έχεις την Trim().

 

>
GreekName gr=new GreekName();
gr.Text=null;

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Ευχαριστώ για την απάντηση.

 

Οπότε αν σε ερμηνεύω σωστά, δεν υπάρχει απολύτως καμία διαφορά αν χρησιμοποιήσουμε ή όχι το this, είναι καθαρά θέμα readability και μόνο χωρίς καμία άλλη επίπτωση ή όφελος, σωστά;

 

Σχετικά με τα optional parameters, συμπτωματικά τα κοίταγα σήμερα το πρωί από το ίδιο link, αλλά με χάλασε αυτό εδώ...

 

...

If the caller provides an argument for any one of a succession of optional parameters, it must provide arguments for all preceding optional parameters. Comma-separated gaps in the argument list are not supported. For example, in the following code, instance method ExampleMethod is defined with one required and two optional parameters.

 

>
public void ExampleMethod(int required, string optionalstr = "default string", int optionalint = 10)

 

The following call to ExampleMethod causes a compiler error, because an argument is provided for the third parameter but not for the second.

 

//anExample.ExampleMethod(3, ,4);

 

However, if you know the name of the third parameter, you can use a named argument to accomplish the task.

 

anExample.ExampleMethod(3, optionalint: 4);

...

 

Οπότε προτίμησα το overloading, και για να μειώσω όσο μπορούσα το code duplication στους constructor, χρησιμοποιώ στον καθένα τους τον αμέσως προηγούμενο (το ίδιο κάνω και σε κάποια overloaded methods).

 

Αν υπάρχουν άλλα ουσιώδη συγκριτικά πλεονεκτήματα των optional parameters, θα ήθελα αν ξέρει κάποιος να με διαφωτίσει και να αλλάξω αν είναι την υλοποίηση.

 

Τώρα μια άλλη ερώτηση που θα ήθελα να κάνω, ποια είναι η κοινή πρακτική για να αναθέτουμε privately μια τιμή σε ένα private field.

 

Τι εννοώ... θέλω να προσθέσω στην κλάση 2 ακόμα fields: _fname και _lname, τα οποία να έχουν public getters (εύκολο) αλλά αντί για setters θέλω να ενημερώνονται ας το πούμε αυτόματα με το πρώτο και τελευταίο token του _text.

 

Δηλαδή το this._fname να ενημερώνεται αυτόματα με την 1η λέξη (token) του this.Text (ή string.Empty δεν υφίσταται this.Text). Ομοίως το this._lname να ενημερώνεται αυτόματα με το τελευταίο token του this.Text αν υπάρχουν τουλάχιστον 2 tokens στο this.Text (αλλιώς να γίνεται string.Empty).

 

Δεν ρωτάω για τις κλάσεις και τις μεθόδους που θα βρίσκουν τα tokens μέσα στο this.Text, αλλά για την μεθοδολογία υλοποίησης αυτών των ας των πούμε αυτόματων setters.

 

Να τους κάνω private methods, private property setters, κάτι άλλο; Για παράδειγμα είναι καν εφικτό να υλοποιηθεί κάτι τέτοιο ως private setter;

 

Έστω δηλαδή πως το κάνω...

 

>
   /** @brief Property. */
   public string FirstName
   {
       get {
           if ( string.IsNullOrEmpty(this.Text) )
               return (_fname = string.Empty);
           return this.Text.Split(null)[0];
       }
       private set {
           if ( string.IsNullOrEmpty(this.Text) )
               this._fname = string.Empty;
           else
               this._fname = this.Text.Split(null)[0];
       }
   }

 

Μετά πως μπορώ να καλέσω τον setter αυτό; Είναι εφικτό κάτι τέτοιο, ή πρέπει να το κάνω με private μέθοδο; Και που και πότε θα την καλώ;

 

 

EDIT

 

Ωπ, έπεσαν κι άλλες απαντήσεις όσο έγραφα αυτό το ποστ (οπότε σορρυ αν έχουν ήδη απαντηθεί ερωτήσεις μου)

 

@AlbNik:

 

Σωστότατος, thanks!

 

@MitsakosGR:

 

Πολύ ωραίο κόλπο, thanks επίσης!

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

@Chris:

 

 

 

:lol:

 

No problem από μένα (αν είχα πρόβλημα δεν θα το άνοιγα καν ;) ). Άλλωστε όπως γράφω και στο νήμα της C, έχω να ασχοληθώ σοβαρά με OOP γλώσσες από την εποχή των... δεινοσαύρων :lol:, οπότε καλό θα μου κάνει να πονέσω... no pain, no gain :)

 

 

 

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Καταρχήν. Η property είναι απλά μια πιο "καλοντυμένη" συνάρτηση. Για την ακρίβεια είναι ένα καλοντυμένο ζεύγος συναρτήσεων (set/get).

Δεν είναι απαραίτητο να υπάρχει μια private τιμή για κάθε propery. Όπως δεν είναι απαραίτητο να υπάρχει σχέση ενα προς ένα κάθε συνάρτησης με μία μεταβλητή.

θέλω να προσθέσω στην κλάση 2 ακόμα fields: _fname και _lname, τα οποία να έχουν public getters (εύκολο) αλλά αντί για setters θέλω να ενημερώνονται ας το πούμε αυτόματα με το πρώτο και τελευταίο token του _text.

Μπορείς να έχεις μια property για παράδειγμα που οταν την κάνεις get να σου επιστρέφει ένα μέρος ενός private string και όταν την κάνεις set να κάνεις κάτι τελείως διαφορετικό σε άλλο πεδίο.

 

Μπορείς να έχεις π.χ. ένα μονο string _text και 2 properties που η κάθε μια να επιστρέφει διαφορετικό μέρος αυτού του string (αν υπάρχει).

 

 

Δηλαδή τι ακριβώς θες να γίνεται όταν θα κάνεις

 

>
ob.FirstName = "kostas";

(Στο set δίνεις κάτι. Διαφορετικά δεν είναι set.)

 

Σκέψου σαν να μεταφράζεται το παραπάνω ως εξής

>
// Ο setter καταρχήν μεταφράζεται ώς
public void setFirstName(String value);

//Και όταν καλείται το παραπάνω μεταφράζεται σε
ob.setFirstName("kostas");

 

Θες να μπορεί να γίνει αυτό καταρχήν; Αν όχι μπορείς να μην φτιάξεις setter.

Θες το string που θα δοθεί κατα το set να "μπεί" μέσα στην αντίστοιχη θέση στο _text;

 

Τώρα, νομίζω δεν κατάλαβα καλά τι θες να κάνεις (και σορρυ αν απαντάω άσχετα) όμως το βρίσκω συμαντικό να αναφέρω το εξής.

 

Γενικότερα το string είναι μια διαφορετική φιλοσοφία στη C# (όπως και στη Java και δε ξέρω που αλλού).

Δεν μπορείς σχεδόν ποτέ να το πειράξεις αυτό το ίδιο. Να παρεμβάλεις μέσα του δηλαδή ένα άλλο string.

Μπορείς να κάνεις χιλιάδες πράγματα (παρεμβολή, αποκοπή, αντικατάσταση) αλλά όλα θα σου δώσουν ένα νεο string με το αποτέλεσμα που θες.

 

EDIT:

όπως για παράδειγμα αυτό

>
return this.Text.Split(null)[0];

Κάνει 2 πράγματα. Φτιάχνει έναν νέο πίνακα με νέα string και από αυτά τα νέα strings αντιγράφεται το πρώτο σε ένα νέο για να επιστραφεί!

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Ο defacer μόλις έφαγε πόνο γιατί ο %$#$#^%$##$@ editor έχασε όλο το κείμενο που έγραφα... οπότε συνοπτικά και σε δεύτερο χρόνο αν χρειάζεται δίνω εξηγήσεις.

 

Στα members της τρέχουσας class βάζε πάντα this, αν και δεν έχει καμία τεχνική διαφορά. Ο λόγος είναι ότι έτσι λέει η Microsoft οπότε ελλείψει πολύ καλού λόγου για το αντίθετο, go with the flow. Αυτό θα βοηθήσει.

 

Στην ονοματολογία το "σωστό" είναι:

 

>private CultureInfo cultureInfo;
private string text;
private string firstName;
private string lastName;

 

(by the way το CultureInfo πού χρειάζεται?)

 

Τα comments σε xmldoc.

 

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

 

>var s = "Trailing spaces ";
foo.Text = s;
if (foo.Text != s) Console.WriteLine("Wait, what?!?!?");

 

To expectation σε μια property είναι πως ο,τι βάλεις, αυτό θα βγάλεις. Αν θέλεις να κάνεις τέτοια και θεωρείς ότι πρέπει να γίνουν στην μέσα στην class (που συνήθως δεν πρέπει) τότε κάνε μια σχετική method. Εκεί δεν υπάρχει expectation.

 

Τους constructors όπως λέει ο mitsakos.

 

Optional parameters σε public members όπως o διάολος το λιβάνι γιατί αν δεν τις δώσεις τότε οι default τιμές τους αποτυπώνονται στο compiled code του call site, επομένως τυχόν αλλαγή στις default τιμές πρέπει να αντιμετωπίζεται ως breaking change. Το ίδιο ισχύει και για τα ονόματα των παραμέτρων επειδή υπάρχουν named arguments!

 

Γενικά στην αρχή μου κακοφάνηκε ότι η C# δεν είχε optional, μετά συνειδητοποίησα πως ήταν μόνο η ιδέα μου και πως χίλιες φορές λίγο παραπάνω duplication (το οποίο μάλιστα δε χρειάζεται καν να κάνεις με το χέρι αν τίθεται θέμα όγκου δουλειάς) παρά ευτράπελα όταν ο client κάνει link με νέα version της assembly σου. Εύχομαι αυτό το feature να μην υπήρχε ούτε στη C++.

 

Τέλος, για το FirstName -- simple is good:

>
public string FirstName
{
get { return this.firstName; }

}
public string Text
{
get { ... }
set
{
 // ....
	 this.firstName = ...;
}
}

 

Και τέλος κάτι γενικό: αν χρησιμοποιείς Visual Studio θα δεις ότι το μέγεθος της βοήθειας που σου παρέχει το IDE (και το tooling γενικότερα) στη C# σε σχέση με τα αντίστοιχα που υπάρχουν για C διαφέρει περίπου όσο διαφέρει ο ήλιος με ένα φακό τσέπης. Για να καταλάβεις για τι πράγμα μιλάω, βάλε ReSharper και γράψε λίγο κώδικα. Αν τυχόν είσαι δύσκολος πελάτης ψάξε να δεις τι επιλογές σου δίνει από τα μενού ή από το help.

 

There is no going back.

 

PS: Τώρα που το βλέπω καλύτερα, δε μου αρέσει αυτό που γίνεται στον constructor που κάνει "μασάζ" στις τιμές των παραμέτρων του. Γενικά το "προσπαθώ να κάνω ο,τι μπορώ" δεν είναι στη φιλοσοφία της c#. Αν δε σου αρέσει αυτό που βλέπεις, throw new ArgumentException ή ArgumentNullException και περάστε έξω παρακαλώ.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Optional parameters σε public members όπως o διάολος το λιβάνι γιατί αν δεν τις δώσεις τότε οι default τιμές τους αποτυπώνονται στο compiled code του call site, επομένως τυχόν αλλαγή στις default τιμές πρέπει να αντιμετωπίζεται ως breaking change. Το ίδιο ισχύει και για τα ονόματα των παραμέτρων επειδή υπάρχουν named arguments!

 

Γενικά στην αρχή μου κακοφάνηκε ότι η C# δεν είχε optional, μετά συνειδητοποίησα πως ήταν μόνο η ιδέα μου και πως χίλιες φορές λίγο παραπάνω duplication (το οποίο μάλιστα δε χρειάζεται καν να κάνεις με το χέρι αν τίθεται θέμα όγκου δουλειάς) παρά ευτράπελα όταν ο client κάνει link με νέα version της assembly σου. Εύχομαι αυτό το feature να μην υπήρχε ούτε στη C++.

 

defacer αν αυτό μπορούσες να το εξηγούσες λίγο με ένα απλό παράδειγμα θα το εκτιμούσα :D

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Ένα-ένα παιδιά, γιατί γενικώς αυτές τις 2 μέρες έχω φάει too much info in too little time :P

 

@moukoublen:

 

Thanks (αν και τα γνώριζα αυτά ;) ).

 

Βασικά αυτό που ρώτησα αν υπάρχει κοινή πρακτική στην C# για ας το πούμε auto-updated private fields. Δηλαδή, θέλω με το που θα κάνεις ας πούμε...

 

>
GreekName name = new GreekName("Μάκης Βοργιάς");

 

να ενημερώνονται "αυτόματα" (implicitly είναι η σωστή λέξη) ως εξής τα private fields...

 

>
_fname = "Μακης"
_lname = "Βοργιάς"

 

Ομοίως κι όταν κάνεις κατόπιν, π.χ..

 

>
name.Text = "Βαγγέλης  Αντύπας";

(να ενημερώνονται και πάλι implicitly τα private fields _fname και _lname).

 

Οπότε η προφανής σε μένα τακτική είναι η ενημέρωσή τους να γίνεται στον setter της Text (την οποία την καλούν και τα constructors της κλάσης).

 

Ρώτησα όμως αν υπάρχει κάποιος άλλος τρόπος που ενδεχομένως είναι καλύτερος ως προσέγγιση και αποτελεί κοινή πρακτική στην C#. Αν υπήρχε κάποιος περίεργος αυτοματισμός/σύνταξη κατά τον οποίο θα μπορούσαμε να καλέσουμε έναν setter χωρίς να περνάμε value κατά την κλήση του, τότε θα μπορούσα να υλοποιήσω τον setter της FirstName όπως έγραψα πριν και να τον καλούσα μέσω της property (με αυτόν τον υποτιθέμενο αυτοματσμό/σύνταξη) στον constructor ή/και στον setter της Text.

 

Είπα να ρωτήσω, γιατί βλέπω διάφορες ωραίες "μαγκιές" στη γλώσσα :)

 

Οπότε, θα το κάνω είτε με κάποιο private method είτε hard-code στον constructor, σωστά;

 

@defacer:

 

Πολλά κι ενδιαφέροντα, thanks! Θα τα διαβάσω με ησυχία και αύριο και θα επανέλθω. Προς το παρόν, για το Culture το έβαλα σκεπτόμενος πως θέλω το πρόγραμμα να τρέχει forced σε ελληνικό περιβάλλον (και όχι στο εκάστοτε CurrentCulture)... δεν ισχύει;

 

Για τα IDE, κατέβασα και VS (2010 στα XP, 2012 στα 7άρια) και MonoDevelop, και SharpDevelop. Προς το παρόν γράφω όμως στο Notepad++.

 

Έριξα μια ματιά και στα 3 IDE αυτές τις 2 μέρες (στο MonoDevelop έκανα και το GTK tutorial και δούλεψε μια χαρά, αλλά το IDE έχει bugs στα Windows). Τα VS δεν τα μπορώ με τίποτα (ενδεχομένως να αλλάξω γνώμη αν αναγκαστώ να δουλέψω μαζί τους σε μεγάλο project). To #develop μου φάνηκε πολύ καλό (διάβασα πως έχει και περισσότερες δυνατότητες από ότι τα VS Express) αλλά προς το παρόν δεν το χρειάζομαι.

 

Οπότε Notepad++ για να γίνω familiar με τη γλώσσα, και με τον compiler της και μετά βλέπουμε (προς το παρόν δεν έχω προβλήματα με το Nodepad++, αλλά επίσης προς το παρόν γράφω toy κώδικα).

 

EDIT:

 

Παρεμπιπτόντως, ορμώμενος από τα constructor-chains του MitsakosGR βρήκα και κάτι αναφορικά με τη χρήση του this, σε αυτό το post: http://www.manjuke.com/2010/12/constructor-chaining-in-c.html όπου στο τέλος αναγράφει με κόκκινα γράμματα...

 

**Please note: If you do not specify anything [in this example we used ‘this’), it will be consider that we are calling the constructor on the base class. And it’s similar to using ‘: base(…)’]

 

Και μου ακούγεται πολύ λογικό, δείχνει δηλαδή να υπάρχει όντως διαφορά αν το χρησιμοποιούμε ή όχι το this (έστω και αν στον δικό μου κώδικα δεν χρησιμοποιώ derived classes, πέρα από το constructor chaining που μου υποδείξατε). Δεν ισχύει;

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Οπότε Notepad++ για να γίνω familiar με τη γλώσσα, και με τον compiler της και μετά βλέπουμε (προς το παρόν δεν έχω προβλήματα με το Nodepad++, αλλά επίσης προς το παρόν γράφω toy κώδικα).

 

Θα σου προτείνω το εξής. Εξανάγκασε τον αυτό σου να δουλέψει με visual studio (έστω και το express) για 10 μέρες.

Σαν στοίχημα. :-)

Και μετά επανεξέτασε.

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

 

Επίσης βγάλε monodevelop και mono. Είναι η opensource υλοποίηση του .net (πολύ καλή) αλλά δε χρειάζεται εφόσον είσαι σε windows να χρησιμοποιήσεις mono.

 

 

Τέλος, έχω υπόψιν μου κάποια βιβλία -και τα έχω σε εξαιρετικής ποιότητας pdf να στα στείλω αν θες- που μου έχουν κάνει πάρα πολύ καλή εντύπωση.

Αν τα θες πες μου να στα στείλω αν και βρίσκονται στα torrents.

 

Μιλώ για τα:

Pro C# 2010 and the .NET 4 Platform, C# 4.0 in a Nutshell (ειδικά αυτό) ή στην 5η έκδοσή του C# 5.0 in a Nutshell για το .net 4.5 και την C# 5, καθώς και πολλά άλλα.

 

EDIT:

Οπότε η προφανής σε μένα τακτική είναι η ενημέρωσή τους να γίνεται στον setter της Text (την οποία την καλούν και τα constructors της κλάσης).

 

Ακριβώς. Δεν βρίσκω κάτι πιο απλό από αυτό π.χ.

 

>

class GreekName
{
   private String _fname = "";
   private String _lname = "";

   public String FirstName
   {
       get { return this._fname; }
   }
   public String LastName
   {
       get { return this._lname; }
   }

   public String Text
   {
       get
       {
           return String.Join(" ", _fname, _lname);
       }
       set
       {
           String[] parts = value.Split(' ');
           if (parts.Length > 0)
               this._fname = parts[0];
           if (parts.Length > 1)
               this._lname = parts[1];
       }
   }

   public GreekName(String fullName)
   {
       this.Text = fullName;
   }
}

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Thanks, θα χρειαστώ καλά βιβλία είναι σίγουρο.

 

Έχω το C# 4.0 The Complete Reference του Herbert Schildt και το Beginnig C# Object Oriented Programming, του Dan Clark που τα θεωρώ πάρα πολύ καλά, αλλά ίσως είναι καλή ιδέα να βρω κάποιο για C# 5.0 που βγήκε τον Αύγουστο νομίζω.

 

 

 

Για το VS (μιλάω πάντα για τα Express)... κατά καιρούς το κατεβάζω, το δοκιμάζω και μετά από 1-2 μέρες το ξανα-σβήνω. Αυτή τη φορά ασχολήθηκα 5-6 ώρες συνολικά (σε 2010 στα XP και 2012 στα 7άρια) και προφανώς δεν τα έσβησα ;)

 

Με χαλάνε, είναι fact. Βασικά δεν με χαλάνε μόνο τα VS, με χαλάνε γενικώς τα "ετσιθελικά έξυπνα" IDE, γιατί έχω μάθει μια ζωή να γράφω κώδικα είτε σε editors είτε σε "ελαφριά" IDE, με μακράν περισσότερα χρόνια αφιερωμένα σε 2: emacs (εκεί ξεκίνησα και συνέχισα για πολλά χρόνια μετά, αλλά πλέον δεν θυμάμαι τίποτα) και Notepad++ (τα τελευταία αρκετά χρόνια).

 

Ειδικά όταν μαθαίνω νέες γλώσσες, το θεωρώ απαραίτητο να την χειρίζομαι από γραμμή εντολών (ή έστω με scripts γραμμής εντολών, που τα φτιάχνω όμως εγώ) ώστε να εξοικειωθώ όχι μόνο με τα options του compiler αλλά και με το γενικότερο command-line tool-chain του.

 

Π.χ. τώρα με την C# το πρώτο-πρώτο πράγμα που έκανα ήταν να βρω τα βασικά command-line options του compiler και ήδη έχω φτιάξει 3 custom scripts: ένα για εκτελέσιμα κονσόλας, ένα για εκτελέσιμα WinApi κι ένα για .DLL assemblies. Ήδη για αυτό το toy-πρόγραμμα που παρέθεσα στο νήμα έχω φτιάξει ένα MyExtras.dll με γενικές ρουτίνες κονσόλας (π.χ. PressEnter(), AskForYesChar() κλπ) και το κάνω reference στο linkage.

 

Αυτές τις διαδικασίες τις κρύβουν τα IDE ενώ εμένα είναι οι πρώτες που με ενδιαφέρουν όταν ξεκινάω νέα γλώσσα. Για τον ίδιο λόγο δεν βιάζομαι ποτέ να πάω σε GUI programming αν δεν αισθανθώ άνετα πρώτα άνετα με τη γλώσσα σε επίπεδο κονσόλας.

 

Όλα αυτά είναι υποκειμενικά στον καθένα, ανάλογα πως έχει συνηθίσει. VS ή κάποιο άλλο βαρύ IDE θα χρησιμοποιήσω αν και όταν χρειαστεί να κάνω π.χ. advanced GUI programming. Προς το παρόν προέχει να εξοικειωθώ με τα βασικά της γλώσσας και του tool-chain της με τον τρόπο που με βολεύει.

 

Μετά είναι πολύ πιθανό να χρησιμοποιήσω αυτό το βιβλίο (που επίσης έχω) σε συνδυασμό με το VS, ώστε να εξοικειωθώ (ή έστω κάποιο παρεμφερές, γιατί το συγκεκριμένο είναι για VS 2008/2010... ή κάποιο σαν αυτό για OpenGL... αυτό δεν το έχω).

 

 

 

 

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

defacer αν αυτό μπορούσες να το εξηγούσες λίγο με ένα απλό παράδειγμα θα το εκτιμούσα :D

 

Πες οτι έχεις μια class A με μια static method Foo που έχει optional parameter int bar = 42 στην assembly a.dll.

 

Εσύ τώρα γράφεις κώδικα σε μια άλλη assembly b.exe (έχοντας κάνει reference την a.dll) και σε κάποιο σημείο καλείς την Foo χωρίς παραμέτρους. Πατάς compile. Τι θα πρέπει να κάνει ο compiler?

 

Αυτό που θα κάνει είναι ότι θα δει το Α.Foo(), θα δει ότι η Foo έχει παράμετρο την οποία δεν δίνεις αλλά είναι optional και στην ουσία θα προσποιηθεί ότι είχες γράψει A.Foo(42).

 

At runtime, όταν η εκτέλεση φτάσει εκεί ο κώδικας που υπάρχει μέσα στην a.dll θα κληθεί και η τιμή του bar θα είναι 42. Όλα καλά μέχρι εδώ.

 

Φαντάσου τώρα ότι σου δίνουν μια νέα έκδοση της a.dll όπου η default τιμή του bar έχει αλλάξει σε 52. Χωρίς να κάνεις recompile το b.exe, αντιγράφεις την καινούρια a.dll πάνω από την παλιά και τρέχεις τo πρόγραμμα. Τι θα γίνει;

 

Και πάλι, θα κληθεί η A.Foo με παράμετρο 42 -- προφανές, εφόσον αυτό το 42 έχει γίνει hardcode μέσα στο b.exe. Αυτό είναι κάτι που πιθανότατα δεν περίμενες και σίγουρα δεν ήθελες (εφόσον ο λόγος για τον οποίο δεν έβαλες την παράμετρο ήταν να χρησιμοποιηθεί η default τιμή). Αν όμως αντί για default παράμετρο υπήρχε ένα overload χωρίς παραμέτρους, τότε αυτό το 42 ή 52 δεν είναι ποτέ hardcoded στo b.exe αλλά βρίσκεται στο a.dll που σε κάποια φάση λέει

 

>public void Foo() { Foo(42); }

 

Κάτι ανάλογο γίνεται και όταν κάνεις override μια virtual function αλλάζοντας την τιμή κάποιας default παραμέτρου:

 

>
class Base
{
public virtual void Foo(int x = 42)
{
 Console.WriteLine("Base: " + x);
}
}

class Derived : Base
{
public override void Foo(int x = 52)
{
 Console.WriteLine("Derived: " + x);
}
}

var d = new Derived();
var b = (Base)d;
d.Foo();
b.Foo(); // surprise!

 

Εδώ το πρόβλημα είναι πως η επιλογή της μεθόδου που θα τρέξει γίνεται at runtime (virtual dispatch), όμως η επιλογή της τιμής της παραμέτρου γίνεται statically στο compilation. Εφόσον το b statically είναι τύπου Base, η b.Foo() θα τυπώσει "Derived: 42".

 

Τα ίδια πράγματα ακριβώς ισχύουν και στη C++ (και γι' αυτό γενικά αυτή η πρακτική απαγορεύεται δια ροπάλου). Και γι' αυτό τελικά θα προτιμούσα να μην έχει καμία γλώσσα αυτό το feature ή "feature", όπως θέλεις πες το.

 

Όσον αφορά τα named parameters, αν έχουμε μια static void Foo(string s = null, int i = 42) και πάλι όταν εσύ λες A.Foo(i: 42) ο compiler πάει και βλέπει τα metadata της A.Foo και αφού βρει ποιά είναι η θέση της παραμέτρου i ξαναγράφει το call σα να είχες γράψει A.Foo(null, 42) -- πράγμα που μπορεί να έχει "ενδιαφέρουσες" συνέπειες αν αργότερα αλλάξει το signature της Foo.

 

Βεβαίως τέτοιου είδους αλλαγές στο public interface κατα κανόνα απαγορεύονται δια ροπάλου ακριβώς για να αποφεύγονται τέτοιου είδους προβλήματα (αν δεις ποτέ π.χ. κάποιο COM interface με όνομα όπως IFoo2 τώρα ξέρεις γιατί απλά δεν άλλαξαν τον ορισμό του IFoo), αλλά νομίζω πως είναι καλύτερα απλά να αποκλείσουμε την πιθανότητα και να πάμε για μπύρες.

 

 

Παρένθεση: όποιος δεν ξέρει τι είναι το LinqPad να το κατεβάσει αμέσως τώρα. Μη σας αποπροσανατολίζει το όνομα, μπορείς να γράψεις ο,τι θέλεις.

 

 

 

Ρώτησα όμως αν υπάρχει κάποιος άλλος τρόπος που ενδεχομένως είναι καλύτερος ως προσέγγιση και αποτελεί κοινή πρακτική στην C#. Αν υπήρχε κάποιος περίεργος αυτοματισμός/σύνταξη κατά τον οποίο θα μπορούσαμε να καλέσουμε έναν setter χωρίς να περνάμε value κατά την κλήση του, τότε θα μπορούσα να υλοποιήσω τον setter της FirstName όπως έγραψα πριν και να τον καλούσα μέσω της property (με αυτόν τον υποτιθέμενο αυτοματσμό/σύνταξη) στον constructor ή/και στον setter της Text.

 

Δεν υπάρχει. Ο setter πάντα παίρνει value. Αν θέλεις κάτι παρόμοιο, κάνεις την dependent property read-only και της θέτεις τιμή μέσα από τον setter της master property, δες το παράδειγμα παραπάνω.

 

Πολλά κι ενδιαφέροντα, thanks! Θα τα διαβάσω με ησυχία και αύριο και θα επανέλθω. Προς το παρόν, για το Culture το έβαλα σκεπτόμενος πως θέλω το πρόγραμμα να τρέχει forced σε ελληνικό περιβάλλον (και όχι στο εκάστοτε CurrentCulture)... δεν ισχύει;

 

Δεν κατάλαβα τι εννοείς "ελληνικό περιβάλλον", αλλά σίγουρα δεν ισχύει το ότι αν βάλεις κάπου ένα CultureInfo field θα αλλάξουν ως δια μαγείας πράγματα κατά την εκτέλεση του προγράμματος.

 

Παρεμπιπτόντως, ορμώμενος από τα constructor-chains του MitsakosGR βρήκα και κάτι αναφορικά με τη χρήση του this, σε αυτό το post: http://www.manjuke.c...ining-in-c.html όπου στο τέλος αναγράφει με κόκκινα γράμματα...

 

Και μου ακούγεται πολύ λογικό, δείχνει δηλαδή να υπάρχει όντως διαφορά αν το χρησιμοποιούμε ή όχι το this (έστω και αν στον δικό μου κώδικα δεν χρησιμοποιώ derived classes, πέρα από το constructor chaining που μου υποδείξατε). Δεν ισχύει;

 

Το συγκεκριμένο blogpost είναι junk in my not so humble opinion. Αυτό που λέει είναι πως αν δεν βάλεις ούτε : this(...) ούτε : base(...) τότε απλά θα κληθεί ο default constructor της base class (που βέβαια θα πρέπει να υπάρχει, γιατί αν όλοι οι base constructors χρειάζονται ορίσματα ο compiler δε θα στη χαρίσει). Από τη στιγμή που είναι φανερό ότι ο συγγραφέας δεν παλεύει πολύ ούτε την αγγλική μή χάνεις το χρόνο σου με τέτοια.

 

Βεβαίως αυτή η χρήση του this δεν έχει καμία σχέση με το this.field = value, όπως και δεν έχει καμία σχέση με τη χρήση του this στις extension methods όπως public static void PrintToConsole(this string s). Απλά το ίδιο keyword κάνει double και triple duty.

 

PS

1. O Albahari (συγγραφέας του C# in a nutshell) είναι και ο συγγραφέας του Linqpad. Δεν έχω διαβάσει τα βιβλία του αλλά ακούγεται ότι είναι πολύ καλά.

2. Δεν πρόκειται να επιμείνω :P αλλά απλά θα πω ότι χωρίς υπερβολή μιλάμε για μια αύξηση της παραγωγικότητας τουλάχιστον μίας τάξης μεγέθους με VS + R# αντί για Notepad++.

  • Like 1
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

@defacer Είσαι ωραίος, ευχαριστώ για το χρόνο σου! Τα optional/named arguments τα χρησιμοποιώ κατά κόρον στην Python η οποία by design δεν έχει αυτό το πρόβλημα. Έχω να πιάσω C# 3 χρόνια τώρα :D Δια ροπάλου επομένως έχεις δίκιο! :D

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

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

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

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

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

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

Σύνδεση

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

Συνδεθείτε τώρα
  • Δημιουργία νέου...