在实现接口的通用抽象类中进行转换

时间:2013-12-04 10:21:24

标签: c# generics

给定基类Coin

public class Coin { }

和两个派生类Coin50CentCoin25Cent

public class Coin50 : Coin { }
public class Coin25 : Coin { }

任务是创建一个CoinMachine的对象(用于硬币交换,例如投入50美分硬币,返回两个25美分硬币),符合以下要求:

  1. CoinMachine必须包含两个Coin25CentCoin50cent个对象的集合。

  2. 集合必须来自具有两种方法的抽象泛型类CoinStack<T>

    void Push(T item); T Pop();

  3. CoinMachine必须如下工作

    CoinMachine.Push(new Coin25()); // puts 25cent in 25c stack
    CoinMachine.Push(new Coin50()); // puts 50cent in 50c stack
    CoinMachine.Pop();      // gets 50cent from 50c stack
    CoinMachine.Pop();      // gets 25cent from 25c stack
    

  4. 这是我的实施 好像我在抽象的CoinStack类中有一个问题。

    namespace ConsoleApplication1
    {
        /* Given condition */
        class Program
        {
            static void Main(string[] args)
            {
                CoinMachine.Push(new Coin25());
                CoinMachine.Push(new Coin50());
                CoinMachine.Pop<Coin50>();
                CoinMachine.Pop<Coin25>();
            }
        }
    
        public class Coin { }
        public class Coin50 : Coin { }
        public class Coin25 : Coin { }
        /* End given condition */
    
        public interface ICoinStack
        {
            T Pop<T>();
            void Push<T>(T item);
        }
    
        /* The problem within this abstract class */
        public abstract class CoinStack<T> : ICoinStack
        {
            private Queue<T> _stack = new Queue<T>();
    
            public T Pop<T>() { return _stack.Dequeue(); }
            public void Push<T>(T item) { _stack.Enqueue(item); }
        }
    
        public class CoinStack50 : CoinStack<Coin50> { }
        public class CoinStack25 : CoinStack<Coin25> { }
    
        public class CoinMachine
        {
            private static Dictionary<Type, ICoinStack> map;
    
            static CoinMachine()
            {
                map = new Dictionary<Type, ICoinStack>()
                {
                    { typeof(Coin50), new CoinStack50() },
                    { typeof(Coin25), new CoinStack25() }
                };
            }
    
            public static T Pop<T>()
            {
                var type = typeof(T);
                return map[type].Pop<T>();
            }
    
            public static void Push<T>(T item)
            {
                var type = typeof(T);
                map[type].Push(item);
            }
        }
    }
    

3 个答案:

答案 0 :(得分:4)

您的问题是ICoinStack有通用方法,例如Push<T>(T item),它基本上表示ICoinStack的实现可以接受任何<{1}} 类型。

但是,在您的实施item中,您希望将CoinStack<T>的{​​{1}}限制为<T> ICoinStack.Push<T>。编译器应该已经给你一个警告,说类型参数<T>与外部类型的类型参数CoinStack<T>具有相同的名称。

您必须修改设计,方法是将T本身设为通用(如T),或将其方法更改为接受/返回ICoinStack(或更好:{{ 1}})而不是ICoinStack<T>

示例:

object

答案 1 :(得分:0)

解决方案是更改此代码:

public interface ICoinStack
{
    T Pop<T>();
    void Push<T>(T item);
}

到此:

public interface ICoinStack
{
    Coin Pop();
    void Push(Coin item);
}

并执行如下:

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);
}

问题是您的代码允许使用具有不同CoinStack实现的单个Coin实例。当您为整个类型(整个CoinStack<T>)指定泛型时,您强制使用在类方法中使用的相同类型(PushPop将只接受相同的T,而不是任何类型,也请注意他们不再需要<T>。)

另请注意泛型类型约束(另请参阅我的问题下面的评论)。这些约束确保您只使用Push类的实例调用PopCoin(与之前可以传递任何类型的代码相反),因此,改进了类型安全

CoinMachine课程中,您必须按如下方式修改PushPop方法:

    // 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);
    }

答案 2 :(得分:0)

以下是我将如何解决它:

public class Coin { }
public class Coin50 : Coin { }
public class Coin25 : Coin { }
/* End given condition */

public interface ICoinStack
{
    T Pop<T>() where T: Coin;
    void Push<T>(T item) where T: Coin;
}

/* The problem within this abstract class */
public abstract class CoinStack : ICoinStack
{
    private Queue<Coin> _stack = new Queue<Coin>();

    public TCoin Pop<TCoin>() where TCoin: Coin { return (TCoin)_stack.Dequeue(); }
    public void Push<TCoin>(TCoin item) where TCoin: Coin { _stack.Enqueue(item); }
}

public class CoinStack50 : CoinStack { }
public class CoinStack25 : CoinStack { }

public class CoinMachine
{
    private static Dictionary<Type, ICoinStack> map;

    static CoinMachine()
    {
        map = new Dictionary<Type, ICoinStack>()
        {
            { typeof(Coin50), new CoinStack50() },
            { typeof(Coin25), new CoinStack25() }
        };
    }

    public static T Pop<T>() where T: Coin
    {
        var type = typeof(T);
        return map[type].Pop<T>();
    }

    public static void Push<T>(T item) where T: Coin
    {
        var type = typeof(T);
        map[type].Push(item);
    }
}