[C#] C# Basics (3) – Interface and Collection

1. Contrasting Interfaces to Abstract Base Classes

Abstract base classes do far more than define a group of abstract methods. They are free to define public, private, and protected state data, as well as any number of concrete methods that can be accessed by the subclasses.

Interfaces, on the other hand, are pure protocol. Interfaces never define state data and never provide an implementation of the methods (if you try, you receive a compile-time error)

2. Explicit Interface Implementation

  

Using explicit interface implementation, you are able to ensure that the object user can only access methods defined by a given interface using the correct interface reference, as well as circumvent possible name clashes.

To illustrate, here is the updated Line class (assume you have updated Hexagon and Circle in a similar manner):

   1: // Using explicit method implementation we are able
   2: // to provide distinct Draw() implementations.
   3: public class Line : Shape, IDraw3D
   4: {
   5:     // You can only call this method from an IDraw3D interface reference.
   6:     void IDraw3D.Draw()
   7:     { Console.WriteLine("Drawing a 3D line..."); }
   8:     // You can only call this at the object level.
   9:     public override void Draw()
  10:     { Console.WriteLine("Drawing a line..."); }
  11: }

  

As you can see, when explicitly implementing an interface member, the general pattern breaks
down to returnValue InterfaceName.MethodName(args). There are a few odds and ends to be aware
of when using explicit interface implementation. First and foremost, you cannot define the explicitly
implemented members with an access modifier
. For example, the following is illegal syntax:

   1: // Nope! Illegal.
   2: public class Line : Shape, IDraw3D
   3: {
   4:     public void IDraw3D.Draw() // <= Error!
   5:     {
   6:     Console.WriteLine("Drawing a 3D line...");
   7:     }
   8:     ...
   9: }

This should make sense. The whole reason to use explicit interface method implementation is to ensure that a given interface method is bound at the interface level. If you were to add the public keyword, this would suggest that the method is a member of the public sector of the class, which defeats the point! Given this design, the caller is only able to invoke the Draw() method defined by the Shape base class from the object level:

   1: // This invokes the overridden Shape.Draw() method.
   2: Line myLine = new Line();
   3: myLine.Draw();

To invoke the Draw() method defined by IDraw3D, we must now explicitly obtain the interface reference using any of the techniques shown previously. For example:

   1: // This triggers the IDraw3D.Draw() method.
   2: Line myLine = new Line();
   3: IDraw3D i3d = (IDraw3D)myLine;
   4: i3d.Draw();

  

3.  IEnumerable / IEnumerator / Iterator Methods

Under .NET 1.x, if you wished to have your custom collections (such as Garage) support foreach like
enumeration, implementing the IEnumerable interface (and possibly the IEnumerator interface) was mandatory. However, C# 2005 offers an alternative way to build types that work with the foreach loop via iterators.
Simply put, an iterator is a member that specifies how a container’s internal items should be
returned when processed by foreach. While the iterator method must still be named GetEnumerator(),
and the return value must still be of type IEnumerator, your custom class does not need to implement
any of the expected interfaces:

   1: public class Garage // No longer implementing IEnumerable!
   2: {
   3:     private Car[] carArray;
   4:     ...
   5:     // Iterator method.
   6:     public IEnumerator GetEnumerator()
   7:     {
   8:         foreach (Car c in carArray)
   9:         {
  10:             yield return c;
  11:         }
  12:     }
  13: }

Notice that this implementation of GetEnumerator() iterates over the subitems using internal
foreach logic and returns each Car to the caller using the new yield return syntax. The yield keyword is used to specify the value (or values) to be returned to the caller’s foreach construct. When the yield return statement is reached, the current location is stored, and execution is restarted from this location the next time the iterator is called.
When the C# compiler encounters an iterator method, it will dynamically generate a nested
class within the scope of the defining type (Garage in this case).

The autogenerated class implements the GetEnumerator(), MoveNext() and Current members on your behalf (oddly, the Reset() method is not, and you will receive a runtime exception if you attempt to call it).

原文地址:https://www.cnblogs.com/fangwenyu/p/1656072.html