#1,066 – Constraining a Type Parameter on a Generic Interface

You can constrain a type parameter on a generic interface so that it can be used only as the output type of methods in the interface and not as a type of any method parameters.  You do this using the out keyword on the type parameter.

        public interface FirstAndLast<out T>
        {
            T First();
            T Last();
            void AddThing(T item);   // won't compile
        }

This seems like an odd thing to do, but ensuring that a particular type parameter is used only as output allows us to later use this generic interface covariantly.  (I’ll explain this in an upcoming post).

Advertisements

#537 – Implement a Generic Interface with a Generic Class

When a class makes use of a generic interface, it can choose to implement the constructed interface, supplying all type parameters for the interface.

public class Farmer : IRememberMostRecent<Joke>

A class can also implement a generic interface, as long as the class itself is generic. Type parameters for the interface are supplied to the class when it is constructed.

    public class Dog<T> : ICanEat<T>

This type parameter (or parameters) can then be used in instance methods that implement the interface.

        // ICanEat.Eat
        public void Eat(T thingToEat)
        {
            // ...
        }

You can also use the type parameter passed to the class in instance methods that are not part of the interface.

        // Not part of the interface
        public void PlayWith(T thingToPlayWith)
        {
            // ...
        }

#536 – Using a Generic Interface

Like classes, interfaces can be generic.  Below is an example of a generic interface with  a single type parameter.

    public interface IRememberMostRecent<T>
    {
        void Remember(T thingToRemember);
        T TellMeMostRecent();
        List<T> PastThings { get; }
    }

When a class implements this interface, it can choose to fully construct the interface (provide a type).

    public class Farmer : IRememberMostRecent<Joke>
    {
        public string Name { get; protected set;  }

        public Farmer(string name)
        {
            Name = name;
            lastJoke = null;
            allJokes = new List<Joke>();
        }

        // IRememberMostRecent implementation
        private Joke lastJoke;
        private List<Joke> allJokes;

        public void Remember(Joke jokeToRemember)
        {
            if (lastJoke != null)
                allJokes.Add(lastJoke);

            lastJoke = jokeToRemember;
        }

        public Joke TellMeMostRecent()
        {
            return lastJoke;
        }

        public List<Joke> PastThings
        {
            get { return allJokes; }
        }
    }

Using the Farmer class:

            Farmer burton = new Farmer("Burton");
            burton.Remember(new Joke("A man walks into a bar.", "Ouch"));
            burton.TellMeMostRecent().Output();

            burton.Remember(new Joke("What's red and invisible?", "No tomatoes"));
            burton.TellMeMostRecent().Output();