Suppose we have some interface X. We can make promises like, "if your class implements interface X, you can pass it to this API." Or perhaps we can go even further and say that if your class implements a certain interface, it can be used by certain C# language features.
Here is a corny example. Suppose there is a "vehicle" interface. It specifies 3 methods, "steer", "brake", and "gas". Now if I put together a class (call it "my_car") that has those methods, I can hand it to some API like:
Drive.take_me_to ( my_car, "Chicago, Illinois" );And it will transport me to the given destination. That is the idea. You make your class comply with some Interface, and you can leverage existing useful API. Now interfaces begin to make sense.
Let's make this concrete and talk about IEnumerable<T>.
Here is some official stuff from Microsoft:
IEnumerable<int> ding = new Example.Dingus ( 5 ); foreach ( int x in ding ) Console.WriteLine ( $"Value: {x}" );Let's see if we can pull it off. I replicate what the Microsoft link above shows, which includes a huge amount of boilerplate and ceremony. Some of the methods are there to satisfy ancient C# versions that do not support generic types. I could play with ripping out some of this. All this is sort of humorous because one of my books claims that the IEnumerable
public interface IEnumerableBut clearly there is more to it than that, in particular we also need to satisfy the IEnumerator: IEnumerable { IEnumerator GetEnumerator (); } public interface IEnumerable { IEnumerator GetEnumerator (); }
Something for a future page -- it is also possible to cobble together an IEnumerable using iterators, which feature the "yield" statement.
The output from the code below is as follows.
Value: 1 Value: 2 Value: 3 Value: 4 Value: 5 All doneWe have gotten rather distracted from the main point, which is showing how we can write some code to satisfy an interface, then "plug it into" the C# language.
using System; // This line is absolutely vital using System.Collections; namespace Example { // A custom class that implements IEnumerable(T). When you implement IEnumerable(T), // you must also implement IEnumerable and IEnumerator(T). public class Dingus : IEnumerableWhew! I pulled my hair out with this, until I added the "using System.Collections;" line. The "dispose" and "reset" sections are entirely ceremony, but are supposed to be essential.{ private int how_many; public Dingus ( int arg ) { how_many = arg; } // Must implement GetEnumerator, which returns a new MyEnumerator. public IEnumerator GetEnumerator() { return new MyEnumerator ( how_many ); } // Must also implement IEnumerable.GetEnumerator, but implement as a private method. private IEnumerator GetEnumerator1() { return this.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator1(); } } // When you implement IEnumerable(T), you must also implement IEnumerator(T), // which will walk through whatever you want to enumerate // Implementing IEnumerator(T) requires that you implement IEnumerator and IDisposable. public class MyEnumerator : IEnumerator { private int _how_many; private int _current; // Constructor public MyEnumerator ( int arg ) { _how_many = arg; } // Implement the IEnumerator(T).Current publicly, but implement // IEnumerator.Current, which is also required, privately. public int Current { get { return _current; } } private object Current1 { get { return this.Current; } } object IEnumerator.Current { get { return Current1; } } // Implement MoveNext and Reset, which are required by IEnumerator. public bool MoveNext() { _current++; if ( _current > _how_many ) return false; return true; } public void Reset() { _current = 0; } // Implement IDisposable, which is also implemented by IEnumerator(T). private bool disposedValue = false; public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!this.disposedValue) { if (disposing) { // Dispose of managed resources. } _current = 0; } this.disposedValue = true; } ~MyEnumerator() { Dispose(disposing: false); } } } namespace HogHeaven { public class Program { public static void Main(string[] args) { IEnumerable ding = new Example.Dingus ( 8 ); foreach ( int x in ding ) Console.WriteLine ( $"Value: {x}" ); Console.WriteLine ( "All done" ); } } } // THE END
Tom's Computer Info / [email protected]