INFS 501 Discrete Mathematics

advertisement
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
Download