![](/img/trans.png)
[英]Perform a 'protected abstract override' for an abstract class which implements a generic interface
[英]Casting in generic abstract class that implements interface
給定基類Coin
public class Coin { }
以及兩個派生類Coin50Cent
和Coin25Cent
public class Coin50 : Coin { }
public class Coin25 : Coin { }
該任務是創建一個CoinMachine
對象(用於硬幣交換,例如投入50美分硬幣將返回兩個25美分硬幣),該對象對應於以下要求:
CoinMachine
必須具有Coin25Cent
和Coin50cent
對象的兩個集合。
集合必須從具有兩個方法的抽象通用類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 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>
指定泛型時,您將在類方法中強制使用相同的類型( Push
和Pop
將僅接受相同的T,而不接受任何類型,還請注意,它們不需要<T>
。)
還請注意通用類型約束(另請參見您的問題下方的我的評論)。 這些約束確保您僅使用Coin
類的實例調用Push
和Pop
(與可以傳遞任何類型的低谷的先前代碼相反),從而提高了類型安全性。
在您的CoinMachine
類中,您必須Push
如下所示編輯Push
和Pop
方法:
// 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.