15
Effective C# 50 Specific Way to Improve Your C# Item 28, 29 Sephiroth.Wang 2012/08/29

Effective C# 50 Specific Way to Improve Your C# Item 28, 29 Sephiroth.Wang2012/08/29

Embed Size (px)

Citation preview

Page 1: Effective C# 50 Specific Way to Improve Your C# Item 28, 29 Sephiroth.Wang2012/08/29

Effective C#50 Specific Way to Improve Your C#

Item 28, 29

Effective C#50 Specific Way to Improve Your C#

Item 28, 29

Sephiroth.Wang

2012/08/29

Page 2: Effective C# 50 Specific Way to Improve Your C# Item 28, 29 Sephiroth.Wang2012/08/29

AgendaAgenda

• Item 28: Avoid Conversion Operators

• Item 29: Use the new Modifier Only When Base Class Updates Mandate It

Page 3: Effective C# 50 Specific Way to Improve Your C# Item 28, 29 Sephiroth.Wang2012/08/29

• Item 28: Avoid Conversion Operators

Page 4: Effective C# 50 Specific Way to Improve Your C# Item 28, 29 Sephiroth.Wang2012/08/29

Avoid Conversion OperatorsAvoid Conversion Operators

• Conversion operators introduce a kind of substitutability between classes. Substitutability means that one class can be substituted for another. This can be a benefit: An object of a derived class can be substituted for an object of its base class, as in the classic example of the shape hierarchy

• Any object can be substituted for an instance of System.Object, the root of the .NET class hierarchy.

Page 5: Effective C# 50 Specific Way to Improve Your C# Item 28, 29 Sephiroth.Wang2012/08/29

Avoid Conversion OperatorsAvoid Conversion Operators

• Side effects that modify the state of the target type won't have the same effect on your type. Worse, if your conversion operator returns a temporary object, the side effects will modify the temporary object and be lost forever to the garbage collector.public class Circle : Shape{ private PointF _center; private float _radius;

public Circle() : this ( PointF.Empty, 0 ) { }

public Circle( PointF c, float r ) { _center = c; _radius = r; }

public override void Draw() { //... }

static public implicit operator Ellipse( Circle c ) { return new Ellipse( c._center, c._center, c._radius, c._radius ); }}

public double ComputeArea( Ellipse e ){ // return the area of the ellipse.}

// call it:Circle c = new Circle( new PointF( 3.0f, 0 ), 5.0f );ComputeArea( c );

Page 6: Effective C# 50 Specific Way to Improve Your C# Item 28, 29 Sephiroth.Wang2012/08/29

Avoid Conversion OperatorsAvoid Conversion Operators

• The pervious sample shows what I mean by substitutability: A circle has been substituted for an ellipse. The ComputeArea function works even with the substitution. You got lucky. But examine this function:

public void Flatten( Ellipse e ){ e.R1 /= 2; e.R2 *= 2;}

// call it using a circle:Circle c = new Circle( new PointF ( 3.0f, 0 ), 5.0f );Flatten( c );

Page 7: Effective C# 50 Specific Way to Improve Your C# Item 28, 29 Sephiroth.Wang2012/08/29

Avoid Conversion OperatorsAvoid Conversion Operators

• Changing the conversion from implicit to explicit only forces users to add a cast to the call:

• Create a constructor to convert the Circle to an Ellipse, the actions are clearer:

• Keeping track of the new object:

Circle c = new Circle(new PointF(3.0f, 3.0f), 5.0f);Flatten((Ellipse)c);

Circle c = new Circle( new PointF( 3.0f, 0 ), 5.0f );Flatten ( new Ellipse( c ));

Circle c = new Circle( new PointF( 3.0f, 0 ), 5.0f );// Work with the circle.// ...

// Convert to an ellipse.Ellipse e = new Ellipse( c );Flatten( e );

Page 8: Effective C# 50 Specific Way to Improve Your C# Item 28, 29 Sephiroth.Wang2012/08/29

Avoid Conversion OperatorsAvoid Conversion Operators

• Conversion operators that return fields inside your objects will not exhibit this behavior. They have other problems. You've poked a serious hole in the encapsulation of your class. By casting your type to some other object, clients of your class can access an internal variable. That's best avoided for all the reasons discussed in Item 23.

Page 9: Effective C# 50 Specific Way to Improve Your C# Item 28, 29 Sephiroth.Wang2012/08/29

SummarySummary

• As title, avoid conversion operators

Page 10: Effective C# 50 Specific Way to Improve Your C# Item 28, 29 Sephiroth.Wang2012/08/29

• Item 29: Use the new Modifier Only When Base Class Updates Mandate It

Page 11: Effective C# 50 Specific Way to Improve Your C# Item 28, 29 Sephiroth.Wang2012/08/29

Use the new Modifier Only When Base Class Updates Mandate ItUse the new Modifier Only When Base Class Updates Mandate It

• If you call the same function on the same object, you expect the same code to execute. The fact that changing the reference, the label, that you use to call the function changes the behavior feels very wrong. It's inconsistent.

public class MyClass{ public void MagicMethod( ) { // details elided. }}

public class MyOtherClass : MyClass{ // Redefine MagicMethod for this class. public new void MagicMethod( ) { // details elided }}

Page 12: Effective C# 50 Specific Way to Improve Your C# Item 28, 29 Sephiroth.Wang2012/08/29

Use the new Modifier Only When Base Class Updates Mandate ItUse the new Modifier Only When Base Class Updates Mandate It

• Since the keyword “New” just hide the Class1, but the Test() is exactly exist in two class.

public class Class1 { // 多加一個方法 public void PreTest() { Console.WriteLine("PreTest()"); Test(); } public void Test() { Console.WriteLine("Class1.Test()"); } }

public class Class2 : Class1 { public new void Test() { Console.WriteLine("Class2.Test()"); } }

class Program { static void Main(string[] args) { Class2 c = new Class2(); // 改成呼叫 c.PreTest() c.PreTest();// 出現卻是 Class1.Test()!!? } }

Page 13: Effective C# 50 Specific Way to Improve Your C# Item 28, 29 Sephiroth.Wang2012/08/29

Use the new Modifier Only When Base Class Updates Mandate ItUse the new Modifier Only When Base Class Updates Mandate It

• The recommendation to avoid using the new modifier to redefine nonvirtual functions should not be interpreted as a recommendation to make everything virtual when you define base classes

public class MyWidget : BaseWidget{ public void DoWidgetThings( ) { // details elided. }}

public class BaseWidget{ public void DoWidgetThings() { // details elided. }}

public class MyWidget : BaseWidget{ public void DoMyWidgetThings( ) { // details elided. }}

public class MyWidget : BaseWidget{ public new void DoWidgetThings( ) { // details elided. }}

1

2

Page 14: Effective C# 50 Specific Way to Improve Your C# Item 28, 29 Sephiroth.Wang2012/08/29

Use the new Modifier Only When Base Class Updates Mandate ItUse the new Modifier Only When Base Class Updates Mandate It

• If you have access to the source for all clients of the MyWidget class, you should change the method name because it's easier in the long run. However, if you have released your MyWidget class to the world, that would force all your users to make numerous changes. That's where the new modifier comes in handy

Page 15: Effective C# 50 Specific Way to Improve Your C# Item 28, 29 Sephiroth.Wang2012/08/29

SummarySummary

• Prefer use the “override” than “New”.