在实现接口的通用抽象类中进行投射
给定一个基类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 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>
,你强制执行类方法中使用的相同类型( 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);
}
链接地址: http://www.djcxy.com/p/75921.html
上一篇: Casting in generic abstract class that implements interface
下一篇: Generate libreoffice text document programmatically from template