C# 将项目从一个阵列移动到另一个阵列的优雅技术

C# 将项目从一个阵列移动到另一个阵列的优雅技术,c#,arrays,pass-by-reference,C#,Arrays,Pass By Reference,背景:纸牌游戏;我想以一种干净的方式将牌从一副牌中分发给游戏中的每个玩家 这就是我的想法: public static CardGame.IGame DealAll(this CardGame.IGame objThis, CardGame.Card[] cards) { if (objThis.Players.Length > 0) { for (int i = 0; i < cards.Length; i++)

背景:纸牌游戏;我想以一种干净的方式将牌从一副牌中分发给游戏中的每个玩家

这就是我的想法:

public static CardGame.IGame DealAll(this CardGame.IGame objThis, CardGame.Card[] cards)
    {
        if (objThis.Players.Length > 0)
        {
            for (int i = 0; i < cards.Length; i++)
            {
                objThis.Deck.MoveTo(cards[i], objThis.CurrentPlayer.Hand);

                objThis.AdvancePlayer();
            }
        }

        return objThis;
    }

public static Card[] MoveTo(this Card[] objThis, Card card, Card[] cards)
    {
        List<Card> lstCards = cards.ToList();
        List<Card> lstThis = objThis.ToList();

        lstThis.Remove(card);
        lstCards.Add(card);

        objThis = lstThis.ToArray();
        cards = lstCards.ToArray();

        return cards;
    }
public static CardGame.IGame dealll(此CardGame.IGame对象,CardGame.Card[]卡)
{
如果(objThis.Players.Length>0)
{
对于(int i=0;i
当然,您可以看到参考问题。使用ref关键字会导致一些不太好看的代码,但这可能是不可避免的。有什么建议吗


我更喜欢一个足够灵活的解决方案来处理其他“传牌”情况(玩家将牌打到牌堆,将牌从牌堆移动到“垃圾”牌堆等)。

好吧,一个简单的方法是首先不使用数组。从一开始就使用列表,你不需要重新分配等等-只需从牌堆中移除并添加到手上即可。你可能想考虑使用“<代码>队列>代码>。 更实用的方法是使用不可变集合和ref参数,但如果没有一些好的不可变集合类,这就不太实用。(它们是可用的,但没有内置到框架中。)

为什么要将卡片数组传递到方法中?难道它不应该处理甲板上的所有东西吗?在这一点上,更容易写:

foreach (Card card in deck)
{
    CurrentPlayer.Hand.Add(card);
    AdvancePlayer();
}
deck.Clear();

(顺便说一句,我不知道你为什么在这里使用扩展方法。这看起来更适合作为实例方法。)

好吧,一个简单的方法是首先不使用数组。从一开始就使用列表,你不需要重新分配等等-只需从牌堆中移除并添加到手上即可。你可能想考虑使用“<代码>队列>代码>。 更实用的方法是使用不可变集合和ref参数,但如果没有一些好的不可变集合类,这就不太实用。(它们是可用的,但没有内置到框架中。)

为什么要将卡片数组传递到方法中?难道它不应该处理甲板上的所有东西吗?在这一点上,更容易写:

foreach (Card card in deck)
{
    CurrentPlayer.Hand.Add(card);
    AdvancePlayer();
}
deck.Clear();

(顺便说一句,我不知道你为什么要在这里使用扩展方法。这看起来更适合作为实例方法。)

我认为这对于
数组来说是一个糟糕的情况,数组通常不会被重复地添加和删除。此外,我不会将此作为扩展方法,因为它与应用程序中的几个选定位置无关

考虑只使用一个列表,并使用一个负责移动的类方法

public class CardDealer {
...
  private List<Card> _deck;

  // Put the card [c] into [hand], and remove it from the deck.
  public void Deal(List<Card> hand, Card c) {
    _deck.Remove(c);
    hand.Add(c);
  }
}
公共级信用卡经销商{
...
私人名单;
//将卡[c]放入[手],并将其从牌组中取出。
公开作废交易(名单手、c卡){
_甲板。拆除(c);
另加(c);
}
}
评论者建议将一副牌最好建模为一个队列,这是一个合理的点,取决于你是否只能从牌堆顶部取牌。如果是这样的话,考虑一下:

public class CardDealer {
...
  private Queue<Card> _deck;

  // Put the top card of the deck into the specified hand.
  public void Deal(List<Card> hand) {
    // Deck is a Queue now. No need to specify which card to take.
    Card c = _deck.Dequeue(); 
    hand.Add(c);
  }
}
公共级信用卡经销商{
...
专用队列甲板;
//将牌组顶部的牌放入指定的手牌中。
公开作废交易(挂牌交易){
//牌组现在是一个队列。无需指定要拿哪张牌。
卡片c=_deck.Dequeue();
另加(c);
}
}

我认为这对于
数组来说是一个糟糕的情况,它通常不会被重复地添加和删除。此外,我不会将此作为扩展方法,因为它与应用程序中的几个选定位置无关

考虑只使用一个列表,并使用一个负责移动的类方法

public class CardDealer {
...
  private List<Card> _deck;

  // Put the card [c] into [hand], and remove it from the deck.
  public void Deal(List<Card> hand, Card c) {
    _deck.Remove(c);
    hand.Add(c);
  }
}
公共级信用卡经销商{
...
私人名单;
//将卡[c]放入[手],并将其从牌组中取出。
公开作废交易(名单手、c卡){
_甲板。拆除(c);
另加(c);
}
}
评论者建议将一副牌最好建模为一个队列,这是一个合理的点,取决于你是否只能从牌堆顶部取牌。如果是这样的话,考虑一下:

public class CardDealer {
...
  private Queue<Card> _deck;

  // Put the top card of the deck into the specified hand.
  public void Deal(List<Card> hand) {
    // Deck is a Queue now. No need to specify which card to take.
    Card c = _deck.Dequeue(); 
    hand.Add(c);
  }
}
公共级信用卡经销商{
...
专用队列甲板;
//将牌组顶部的牌放入指定的手牌中。
公开作废交易(挂牌交易){
//牌组现在是一个队列。无需指定要拿哪张牌。
卡片c=_deck.Dequeue();
另加(c);
}
}

也许是这样的

interface ICardPile
{
    ICollection<Card> Cards
    {
        get;
    }
}

interface IOrderedCardPile : ICardPile // FIXME Better name.
{
}

class Deck : ICardPile
{
    private Stack<Card> _cards = new Stack<Card>();

    ICollection<Card> Cards
    {
        get
        {
            return _cards;
        }
    }

    public Deck()
    {
        // TODO Fill deck.
    }

    public void DealCardsTo(IEnumerable<ICardPile> piles, int cardCount)
    {
        for(int i = 0; i < cardCount; ++i)
        {
            foreach(var pile in piles)
                Cards.MoveSomeTo(piles, 1);
        }
    }
}

class Hand : IOrderedCardPile
{
    private HashSet<Card> _cards = new HashSet<Card>();

    ICollection<Card> Cards
    {
        get
        {
            return _cards;
        }
    }
}


也许是这样的

interface ICardPile
{
    ICollection<Card> Cards
    {
        get;
    }
}

interface IOrderedCardPile : ICardPile // FIXME Better name.
{
}

class Deck : ICardPile
{
    private Stack<Card> _cards = new Stack<Card>();

    ICollection<Card> Cards
    {
        get
        {
            return _cards;
        }
    }

    public Deck()
    {
        // TODO Fill deck.
    }

    public void DealCardsTo(IEnumerable<ICardPile> piles, int cardCount)
    {
        for(int i = 0; i < cardCount; ++i)
        {
            foreach(var pile in piles)
                Cards.MoveSomeTo(piles, 1);
        }
    }
}

class Hand : IOrderedCardPile
{
    private HashSet<Card> _cards = new HashSet<Card>();

    ICollection<Card> Cards
    {
        get
        {
            return _cards;
        }
    }
}


我没听说过排队课,但我会查一查。我忘了提到这一点,但我想在其他“传牌”情况下(打牌、将牌移到“垃圾”牌组等)使用足够灵活的方法。扩展方法似乎很合适。我想这样你会得到更多的复杂代码。我会认真建议以最简单的方式写它,然后考虑重用,当你实际上在多个地方得到类似的代码。FWIW,我同意乔恩。当您需要扩展类的行为而无法控制它时,应该使用扩展方法。但是您不需要扩展集合的行为;你只想做一些涉及收集的事情。我没有听说过队列类,但我会去看看。我忘了提到这一点,但我想要一些足够灵活的东西,以便在其他“传卡”情况下使用