簡體   English   中英

強制轉換實現接口的通用抽象類

[英]Casting in generic abstract class that implements interface

給定基類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 

這是我的實現,似乎在轉換抽象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 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);
}

問題是您的代碼允許使用具有不同Coin實現的單個CoinStack實例。 當您為整個類型(整個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);
    }

這是我要解決的方法:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM