我正在开发一个用于纸牌游戏的库。我花了几个小时学习索引器,所以我可以使用一个类似于卡类型的Deck类。然后我通过继承ArrayList实现了同样的事情和更多。因此,我想问为什么当通过“:ArrayList”可以实现同样的事情(以及更多)时,人们会遇到使类成为可索引的麻烦。
我认为我的问题非常自我解释,但对于那些喜欢看代码的人来说。
这是我的Deck类,它包含一个索引器:
class DeckIndexer
{
private Card[] myData;
private int arrSize;
public DeckIndexer(int size)
{
arrSize = size;
myData = new Card[size];
for (int i = 0; i < size; i++)
{
myData[i] = null;
}
}
public Card this[int pos]
{
get
{
return myData[pos];
}
set
{
myData[pos] = value;
}
}
public Card this[Card c]
{
get
{
int count = 0;
for (int i = 0; i < arrSize; i++)
{
if (myData[i] == c)
{
count++;
}
}
return c;
}
set
{
for (int i = 0; i < arrSize; i++)
{
if (myData[i] == c)
{
myData[i] = value;
}
}
}
}
}
现在这是第二个解决方案,继承自ArrayList
class DeckInheritence : ArrayList
{
}
第二种解决方案为我提供了20多种免费,[]语法方法,并为我节省了许多代码行。第一个给我[]语法,附加到object的方法,很难实现。
顺便说一句,是的,我可以看到ArrayList给了我一个对象数组,而不是卡片,但没有太多的捏造让它需要一个卡片类型。
答案 0 :(得分:2)
从根本上说,Deck
不 ArrayList
或List<Card>
。您是否希望呼叫者能够添加任意数量的卡?我对此表示怀疑。空值或重复值怎么样?再一次,不太可能有用。
这是使用合成而不是继承的完美情况。我不会直接在类型中使用数组 - 我使用List<T>
- 但你几乎肯定想为你的套牌编写更多特定于域的代码。有明显的限制,特定于卡组的操作等。您真的希望能够访问卡组中的任何项吗?例如,我希望你能够为玩家提供套牌,然后将其洗牌。
目标应该是创建一个尽可能恰当地代表您的域的类型 - 而不是为您提供代码最少的索引器。
答案 1 :(得分:1)
首先,除非您使用的是.NET 1.1,否则List<Card>
会更好。但是,至于继承...如果您所做的只是代表一个卡片列表,我会只使用 List<Card>
(既没有封装也没有继承)。
至于为什么;当作为列表不是类型的主要目的时,封装很有用,但是对于调用者来说,访问一些方法(如索引器)很有用。正如Jon指出的那样,继承并不(例如)让您可以控制用户对您的数据做什么。
就个人而言,我不建议继承List<T>
(或ArrayList
);将实现细节绑定到实际的类型声明中(更改继承是一个重大变化)。
如果你想用最少的工作来暴露很多方法,你需要做的只是提供IEnumerable<T>
(作为一个接口) - 然后所有的LINQ都可用。所以如果你需要定制的东西(超过List<Card>
)我的建议是:
List<T>
(即私有字段)IEnumerable<T>
(只需返回theList.GetEnumerator()
)