INFS 501 Discrete Mathematics
Download
Report
Transcript INFS 501 Discrete Mathematics
Effective C#, Chapter 1:
C# Language Elements
Last Updated: Fall 2011
Agenda
Material From Bill Wagner
Cover Items 6 and 9
2
Effective C#: 50 Specific Ways to Improve
Your C#
Goal: Compare/Contrast with Java
C# Language Elements
Item 6: Distinguish Between Value
Types and Reference Types
Structs or Classes?
Impacts both correctness and performance
C++ Objects use Struct model
Java Objects use Class model
C# Wants to have it both ways
3
Plus pointers…
Question: Is this a good idea?
C# Language Elements
Objections to Reference Types
Setters and getters need copies
C# value types make copies by default
4
Storing or returning references breaks
encapsulation
But value types are not polymorphic!
C# requires you to decide, upfront, between
value and reference type
Note Bloch’s Java solution
Favor Immutability
C# Language Elements
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);
5
C# Language Elements
Item 9: Understand Relationship
Among the Many Equals
C# Defines 4 different equality tests
Complexity is due to value type/reference
type distinction
Interesting bottom line in case where C#
and Java overlap
6
You can redefine any of them
But you shouldn’t
Wagner and Bloch disagree!
We should understand why
C# Language Elements
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 );
7
C# Language Elements
First, the Easy Cases
Redefining ReferenceEquals is like
redefining Java’s “==“ operator
8
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
C# Language Elements
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?
9
Wagner’s recipe violates this property
C# Language Elements
Wagner’s Recipe
public override bool Equals( object right ) {
// check null
if (right == null) return false;
// in class MyType
// 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 );
}
10
C# Language Elements
Why Does Wagner Use Exact
Type Matches?
Remember the result in Bloch:
Bloch’s approach:
11
Not possible to extend an instantiable class,
add abstract state, and satisfy symmetry,
transitivity, and substitution principles.
Favor composition over inheritance
Save inheritance for interfaces
Wagner’s approach
Sacrifice substitution principle
C# Language Elements
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)
12
C# Language Elements