Download presentation
Presentation is loading. Please wait.
Published byImogen Crawford Modified over 9 years ago
1
Effective C#, Chapter 1: C# Language Elements Last Updated: Fall 2011
2
C# Language Elements 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
C# Language Elements 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
C# Language Elements 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# Language Elements 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
C# Language Elements 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
C# Language Elements 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
C# Language Elements 8 First, the Easy Cases Redefining ReferenceEquals 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
C# Language Elements 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
C# Language Elements 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
C# Language Elements 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
C# Language Elements 12 Problem with Wagner’s Recipe public static bool myCheck (List 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)
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.