Skip to content

Commit

Permalink
Revisions to inheritance topic.
Browse files Browse the repository at this point in the history
  • Loading branch information
rpetrusha committed Dec 13, 2016
1 parent 25164fa commit efa646a
Show file tree
Hide file tree
Showing 10 changed files with 208 additions and 256 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 18 additions & 8 deletions docs/csharp/tutorials/inheritance.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
---
title: Inheritance in C#
description: inheritance
description: Learn to use inheritance in C# libraries and applications.
keywords: inheritance (C#), base classes, derived classes, abstract base classes
author: rpetrusha
manager: wpickett
ms.author: ronpet
ms.date: 12/8/2016
ms.date: 12/13/2016
ms.topic: article
ms.prod: .net-core
ms.technology: .net-core-technologies
Expand Down Expand Up @@ -44,15 +44,25 @@ C# and .NET support *single inheritance* only. That is, a class can only inherit

Not all members of a base class are inherited by derived classes. The following members are not inherited:

- [Constructors](../programming-guide/classes-and-structs/constructors.md), which are called to create a new instance of the class. Each class must define its own constructors.
- [Static constructors](../programming-guide/classes-and-structs/static-constructors.md), which initialize the static data of a class.

- [Destructors](../programming-guide/classes-and-structs/destructors.md), which are called by the runtime's garbage collector to destroy instances of a class.
- [Instance constructors](../programming-guide/classes-and-structs/constructors.md), which you call to create a new instance of the class. Each class must define its own constructors.

- [Static members](../programming-guide/classes-and-structs/static-classes-and-static-class-members.md). Only instance members are inherited by base classes.
- [Destructors](../programming-guide/classes-and-structs/destructors.md), which are called by the runtime's garbage collector to destroy instances of a class.

- [Private](../language-reference/keywords/private.md) and [internal](../language-reference/keywords/internal.md) members. However, internal members of a base class may be *visible* to a derived class if the two types are in the same assembly.

Derived classes inherit all public instance members of the base class, and inherited members can be called just as if they were defined in the derived class. In the following example, class `A` defines a method named `Method1`, and class `B` inherits from class `A`. The example then calls `Method1` as if it were an instance method on `B`.
While all other members of a base class are inherited by derived classes, whether they are visible or not depends on their accessibility. A member's accessibility affects its visibility for derived classes as follows:

- [Private](../language-reference/keywords/private.md) members are visible only in derived classes that are nested in their base class. Otherwise, they are not visible in derived classes. In the following example, `A.B` is a nested class that derives from `A`, and `C` derives from `A`. The private `A.value` field is visible in A.B. However, if you remove the comments from the `C.GetValue` method and attempt to compile the example, it produces compiler error CS0122: "'A.value' is inaccessible due to its protection level."

[!CODE [Inheritance](../../../samples/snippets/csharp/tutorials/inheritance/private.cs#1)]

- [Protected](../language-reference/keywords/protected.md) members are visible only in derived classes.

- [Internal](../language-reference/keywords/protected.md) members are visible only in derived classes that are located in the same assembly as the base class. They are not visible in derived classes located in a different assembly from the base class.

- [Public] (../language-reference/keywords/protected.md) members are visible in derived classes and are part of the derived class' public interface. Public inherited members can be called just as if they were defined in the derived class. In the following example, class `A` defines a method named `Method1`, and class `B` inherits from class `A`. The example then calls `Method1` as if it were an instance method on `B`.

[!CODE [Inheritance](../../../samples/snippets/csharp/tutorials/inheritance/basics.cs#1)]

Expand Down Expand Up @@ -111,15 +121,15 @@ To see what implicit inheritance means, let's define a new class, `SimpleClass`,

[!CODE [Inheritance](../../../samples/snippets/csharp/tutorials/inheritance/simpleclass.cs#1)]

We can then use reflection (which lets us inspect a type's metadata to get information about that type) to get a list of the members that belong to the `SimpleClass` type. Although we haven't defined any members in our `SimpleClass` class, output from the example indicates that it actually has seven members. One of these is a parameterless (or default) constructor that is automatically supplied by the C# compiler. The other six are members of @System.Object, the type from which all classes and interfaces in the .NET type system ultimately implicitly inherit.
We can then use reflection (which lets us inspect a type's metadata to get information about that type) to get a list of the members that belong to the `SimpleClass` type. Although we haven't defined any members in our `SimpleClass` class, output from the example indicates that it actually has nine members. One of these is a parameterless (or default) constructor that is automatically supplied for the `SimpleClass` type by the C# compiler. The eight seven are members of @System.Object, the type from which all classes and interfaces in the .NET type system ultimately implicitly inherit.

[!CODE [Inheritance](../../../samples/snippets/csharp/tutorials/inheritance/simpleclass.cs#2)]

Implicit inheritance from the @System.Object class makes these methods available to the `SimpleClass` class:

- The public `ToString` method, which converts a `SimpleClass` object to its string representation, the fully qualified type name. In this case, the `ToString` method returns the string "SimpleClass".

- The public `Equals` method, which tests two objects to determine whether they are equal. The method tests for reference equality; that is, to be equal, two object variables must refer to the same object.
- Three methods that test for equality of two objects: the public instance `Equals(Object)` method, the public static `Equals(Object, Object)` method, and the public static `ReferenceEquals(Object, Object)` method. By default, these methods test for reference equality; that is, to be equal, two object variables must refer to the same object.

- The public `GetHashCode` method, which computes a value that allows an instance of the type to be used in hashed collections.

Expand Down
Binary file modified docs/csharp/tutorials/media/book-class.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/csharp/tutorials/media/publication-class.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
78 changes: 25 additions & 53 deletions samples/snippets/csharp/tutorials/inheritance/base-and-derived.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,6 @@ public abstract class Publication
{
private bool published = false;
private DateTime datePublished;
private string pubName;
private string pubTitle;
private PublicationType pubType;
private string copyrName;
private int copyrDate;
private int totalPages;

public Publication(string title, string publisher, PublicationType type)
Expand All @@ -21,31 +16,27 @@ public Publication(string title, string publisher, PublicationType type)
throw new ArgumentNullException("The publisher cannot be null.");
else if (String.IsNullOrWhiteSpace(publisher))
throw new ArgumentException("The publisher cannot consist only of whitespace.");
pubName = publisher;
Publisher = publisher;

if (title == null)
throw new ArgumentNullException("The title cannot be null.");
else if (String.IsNullOrWhiteSpace(title))
throw new ArgumentException("The title cannot consist only of whitespace.");
pubTitle = title;
Title = title;

pubType = type;
Type = type;
}

public string Publisher
{ get { return pubName; } }
public string Publisher { get; }

public string Title
{ get { return pubTitle; } }
public string Title { get; }

public PublicationType Type
{ get { return pubType; } }
public PublicationType Type { get; }

public string CopyrightName
{ get { return copyrName; } }
public string CopyrightName { get; private set; }

public int CopyrightDate
{ get { return copyrDate; } }
{ get; private set; }

public int Pages
{ get { return totalPages; }
Expand Down Expand Up @@ -77,19 +68,15 @@ public void Copyright(string copyrightName, int copyrightDate)
throw new ArgumentNullException("The name of the copyright holder cannot be null.");
else if (String.IsNullOrWhiteSpace(copyrightName))
throw new ArgumentException("The name of the copyright holder cannot consist only of whitespace.");
copyrName = copyrightName;
CopyrightName = copyrightName;

int currentYear = DateTime.Now.Year;
if (copyrightDate < currentYear - 10 || copyrightDate > currentYear + 2)
throw new ArgumentOutOfRangeException(String.Format("The copyright year must be between {0} and {1}",
currentYear - 10, currentYear + 1));
copyrDate = copyrightDate;
throw new ArgumentOutOfRangeException($"The copyright year must be between {currentYear -10} and {currentYear + 1}");
CopyrightDate = copyrightDate;
}

public override string ToString()
{
return Title;
}
public override string ToString() => Title;
}
// </Snippet1>

Expand All @@ -100,16 +87,11 @@ namespace DerivedClasses

public sealed class Book : Publication
{
private string authorName;
private Decimal bookPrice;
private string id;
private string ISOCurrencySymbol;

public Book(string title, string author, string publisher) :
this(title, String.Empty, author, publisher)
{ }

public Book(string title, string isbn, string author, string publisher) : base(publisher, title, PublicationType.Book)
public Book(string title, string isbn, string author, string publisher) : base(title, publisher, PublicationType.Book)
{
// isbn argument must be a 10- or 13-character numeric string without "-" characters.
// We could also determine whether the ISBN is valid by comparing its checksum digit
Expand All @@ -123,36 +105,32 @@ public Book(string title, string isbn, string author, string publisher) : base(p
if (! UInt64.TryParse(isbn, out nISBN))
throw new ArgumentException("The ISBN can consist of numeric characters only.");
}
id = isbn;
ISBN = isbn;

authorName = author;
Author = author;
}

public string ISBN
{ get { return id; } }
public string ISBN { get; }

public string Author
{ get { return authorName; } }
public string Author { get; }

public Decimal Price
{ get { return bookPrice; } }
public Decimal Price { get; private set; }

// A three-digit ISO currency symbol.
public string Currency
{ get { return ISOCurrencySymbol; } }
public string Currency { get; private set; }


// Returns the old price, and sets a new price.
public Decimal SetPrice(Decimal price, string currency)
{
if (price < 0)
throw new ArgumentOutOfRangeException("The price cannot be negative.");
Decimal oldValue = bookPrice;
bookPrice = price;
Decimal oldValue = Price;
Price = price;

if (currency.Length != 3)
throw new ArgumentException("The ISO currency symbol is a 3-character string.");
ISOCurrencySymbol = currency;
Currency = currency;

return oldValue;
}
Expand All @@ -163,18 +141,12 @@ public override bool Equals(object obj)
if (book == null)
return false;
else
return id == book.id;
return ISBN == book.ISBN;
}

public override int GetHashCode()
{
return id.GetHashCode();
}
public override int GetHashCode() => ISBN.GetHashCode();

public override string ToString()
{
return String.Format("{0}{1}", String.IsNullOrEmpty(Author) ? "" : Author + ", ", Title);
}
public override string ToString() => $"{(String.IsNullOrEmpty(Author) ? "" : Author + ", ")}{Title}";
}
// </Snippet2>
}
Expand Down
24 changes: 7 additions & 17 deletions samples/snippets/csharp/tutorials/inheritance/is-a.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,32 @@

public class Automobile
{
public string _make;
public string _model;
public int _year;

public Automobile(string make, string model, int year)
{
if (make == null)
throw new ArgumentNullException("The make cannot be null.");
else if (String.IsNullOrWhiteSpace(make))
throw new ArgumentException("make cannot be an empty string or have space characters only.");
_make = make;
Make = make;

if (model == null)
throw new ArgumentNullException("The model cannot be null.");
else if (String.IsNullOrWhiteSpace(make))
throw new ArgumentException("model cannot be an empty string or have space characters only.");
_model = model;
Model = model;

if (year < 1857 || year > DateTime.Now.Year + 2)
throw new ArgumentException("The year is out of range.");
_year = year;
Year = year;
}

public string Make
{ get { return _make; } }
public string Make { get; }

public string Model
{ get { return _model; } }
public string Model { get; }

public int Year
{ get { return _year; } }
public int Year { get; }

public override string ToString()
{
return String.Format("{0} {1} {2}", _year, _make, _model);
}
public override string ToString() => $"{Year} {Make} {Model}";
}
// </Snippet1>

Expand Down
35 changes: 35 additions & 0 deletions samples/snippets/csharp/tutorials/inheritance/private.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// <Snippet1>
using System;

public class A
{
private int value = 10;

public class B : A
{
public int GetValue()
{
return this.value;
}
}
}

public class C : A
{
// public int GetValue()
// {
// return this.value;
// }
}

public class Example
{
public static void Main(string[] args)
{
var b = new A.B();
Console.WriteLine(b.GetValue());
}
}
// The example displays the following output:
// 10
// </Snippet1>
Loading

0 comments on commit efa646a

Please sign in to comment.