1 / 12

Effective C#, Chapter 1: C# Language Elements

Effective C#, Chapter 1: C# Language Elements. Last Updated: Fall 2011. Agenda. Material From Bill Wagner Effective C#: 50 Specific Ways to Improve Your C# Cover Items 6 and 9 Goal: Compare/Contrast with Java. Item 6: Distinguish Between Value Types and Reference Types.

xiong
Download Presentation

Effective C#, Chapter 1: C# Language Elements

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Effective C#, Chapter 1: C# Language Elements Last Updated: Fall 2011

  2. Agenda • Material From Bill Wagner • Effective C#: 50 Specific Ways to Improve Your C# • Cover Items 6 and 9 • Goal: Compare/Contrast with Java

  3. Item 6: Distinguish Between Value Types and Reference Types • Structs or Classes? • Impacts both correctness and performance • C++ Objects use Struct model • Plus pointers… • Java Objects use Class model • C# Wants to have it both ways • Question: Is this a good idea?

  4. Objections to Reference Types • Setters and getters need copies • Storing or returning references breaks encapsulation • C# value types make copies by default • But value types are not polymorphic! • C# requires you to decide, upfront, between value and reference type • Note Bloch’s Java solution • Favor Immutability

  5. C# Structs vs. Classes // C# Value Type // No polymorphic behavior public struct Employee { private string _name; private decimal _salary; public void Pay (BankAccount b) { b.Balance += _salary }; } // C# Reference Type // Polymorphic behavior public class Employee { private string _name; private decimal _salary; public void Pay (BankAccount b) { b.Balance += _salary }; } // Client code – Note Difference of struct vs. class Employee e1 = Employees.Find(“CEO”); e1.Salary += Bonus; // Is bonus permanent addition to salary? e1.Pay(CEOBankAccount);

  6. Item 9: Understand Relationship Among the Many Equals • C# Defines 4 different equality tests • You can redefine any of them • But you shouldn’t • Complexity is due to value type/reference type distinction • Interesting bottom line in case where C# and Java overlap • Wagner and Bloch disagree! • We should understand why

  7. Four Ways To Test Equality // Object Identity – Never Redefine public static bool ReferenceEquals ( object left, object right ); // Implements Equals() as Dynamic Binding – Never Redefine public static bool Equals ( object left, object right ); // Like Java equals() for C# reference types – Redefine as needed public virtual bool Equals( object right); // Equality for value types // Nothing similar in Java // Goal of redefining is simply to improve performance public static bool operator==( MyClass left, MyClass right );

  8. First, the Easy Cases • RedefiningReferenceEquals is like redefining Java’s “==“ operator • Doesn’t make sense to redefine • static Equals is for dynamic binding • Effect is to invoke nonstatic Equals on left hand argument • Doesn’t make sense to redefine

  9. Interesting Case: virtual Equals() • Same situation as Java’s Equals() method in the Object class • Same set of constraint • Reflexivity • Symmetry • Transitivity • Liskov Substitution Principle? • Wagner’s recipe violates this property

  10. Wagner’s Recipe public override bool Equals( object right ) { // in class MyType // check null if (right == null) return false; // Optimization for comparison to self if (object.ReferenceEquals( this, right )) return true; // Type check that is NOT Bloch’s recipe if (this.GetType() != right.GetType()) return false; // Alternative equivalent to Bloch’s recipe // MyType rightAsMyType = right as MyType; // if (rightAsMyType == null) return false; // Compare this type's contents here // This part is equivalent to Bloch’s recipe return CompareFooMembers( this, right as Foo ); }

  11. Why Does Wagner Use Exact Type Matches? • Remember the result in Bloch: • Not possible to extend an instantiable class, add abstract state, and satisfy symmetry, transitivity, and substitution principles. • Bloch’s approach: • Favor composition over inheritance • Save inheritance for interfaces • Wagner’s approach • Sacrifice substitution principle

  12. Problem with Wagner’s Recipe public static bool myCheck (List<Points> points) { Point p = ... // a Point with value (1,2) return points.Contains(p) } // Suppose the list contains subclasses of Point WITHOUT client // visible state. Then the return value should be true if a // subclass of Point with state (1,2) is in the list. // Reason: This is simply the Liskov Substitution Principle. // Of course, if the list contains subclasses WITH client visible // state, then the return value CANNOT be true if Point(1,2,x) // is in the list. // Reason: Otherwise guaranteed a Symmetry or Transitivity failure. // See Bloch, page 39 for more details of this example (in Java)

More Related