在实现接口的通用抽象类中进行投射

给定一个基类Coin

public class Coin { }

和两个派生类Coin50CentCoin25Cent

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

任务是创建一个CoinMachine的对象(用于兑换硬币,例如将50美分的硬币退回两个25美分的硬币),它们对应以下要求:

  • CoinMachine必须有两个Coin25CentCoin50cent对象的集合。

  • 这些集合必须从具有两种方法的抽象通用类CoinStack<T>派生

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

  • 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
    

  • 这里是我的实现看起来像我在抽象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);
            }
        }
    }
    

    你的问题是ICoinStack有泛型方法,比如Push<T>(T item) ,它基本上说ICoinStack的实现可以接受任何类型的item

    然而,在您的实现CoinStack<T> ,要限制<T>ICoinStack.Push<T><T>CoinStack<T> 。 编译器应该已经给你一个警告,说类型参数T与外部类型的类型参数T具有相同的名称。

    你必须修改你的设计,或者通过使ICoinStack本身是通用的(如ICoinStack<T> ),或者改变它的方法来接受/返回object (或者甚至更好: Coin )而不是T

    例:

    // accept/return Coin instead of T to keep ICoinStack
    // and it's methods non-generic
    public interface ICoinStack
    {
       Coin Pop();
       void Push(Coin item);
    }
    
    // explicit interface implementation and the where T:Coin 
    // constrain help us here to implement ICoinStack
    public abstract class CoinStack<T> : ICoinStack where T:Coin
    {
       private Queue<T> _stack = new Queue<T>();
    
       Coin ICoinStack.Pop() { return _stack.Dequeue(); }
       void ICoinStack.Push(Coin item) { _stack.Enqueue((T)item); }
    
       public T Pop() { return _stack.Dequeue(); }
       public void Push(T item) { _stack.Enqueue(item); }
    }
    
    // we need a cast in Pop<T>, and also the where T:Coin constrain
    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 (T)map[type].Pop();
       }
    
       public static void Push<T>(T item) where T:Coin
       {
           var type = typeof(T);
           map[type].Push(item);
       }
    }
    

    以下是我将如何解决它的方法:

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

    解决方法是更改​​此代码:

    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>了。)

    还请注意泛型类型约束(另请参阅我的评论在您的问题下面)。 这些限制可以确保只使用Coin类的实例(与之前的代码可以通过任何类型的传递槽相反)调用PushPop ,从而提高了类型安全性。

    在您的CoinMachine类中,您必须Push如下方式编辑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);
        }
    
    链接地址: http://www.djcxy.com/p/75921.html

    上一篇: Casting in generic abstract class that implements interface

    下一篇: Generate libreoffice text document programmatically from template