The solution is to change this code:
public interface ICoinStack { T Pop<T>(); void Push<T>(T item); }
:
public interface ICoinStack { Coin Pop(); void Push(Coin item); }
and implementations as follows:
public abstract class CoinStack<T> : ICoinStack where T: Coin { private Queue<T> _stack = new Queue<T>(); public T Pop() { return _stack.Dequeue(); } Coin ICoinStack.Pop() {return this.Pop(); } public void Push(T item) { _stack.Enqueue(item); } void ICoinStack.Push(Coin item) { this.Push((T) item); }
The problem was that your code allowed you to use one instance of CoinStack with different Coin implementations. When you specify generics for the whole type (the whole CoinStack<T> , you use the same type that will be used in class methods ( Push and Pop will only accept the same T, not any type, also note that they no more <T> needed.)
Also note the general type restrictions (see also my comment below your question). These restrictions ensure that you only call Push and Pop with an instance of the Coin class (opposite to the previous code, which can have any type of gutter passed in) and thus have improved type safety.
In your CoinMachine class CoinMachine you must edit the Push and Pop methods as follows:
// notice the generic constraint, as it is required now by the compiler public static T Pop<T>() where T: Coin { var type = typeof(T); // we need a cast, as the `ICoinStack` now return `Coin` return (T) map[type].Pop(); } public static void Push<T>(T item) where T: Coin { var type = typeof(T); map[type].Push(item); }
Ivaylo slavov
source share