C# C:处理这个错误的首选方法是什么?

C# C:处理这个错误的首选方法是什么?,c#,C#,我有一个由两张扑克牌组成的类“手牌”,如下所示: public class Card { public char r, s; public Card(char rank, char suit) { r = rank; s = suit; } } public class Hand { public Card c1, c2; public Hand(Card one, Card two) {

我有一个由两张扑克牌组成的类“手牌”,如下所示:

public class Card
{
    public char r, s;

    public Card(char rank, char suit)
    {
        r = rank;
        s = suit;
    }
}

public class Hand
{
    public Card c1, c2;

    public Hand(Card one, Card two)
    {
        c1 = one;
        c2 = two;
    }
}
在52张牌组中,我们不能有两张相同的牌。我应该如何处理一个错误,当我意外地用两张相同的卡片引用一个类时,例如,啊,啊


谢谢,阿什,甲板上不应该处理吗?例如,您可以有一个pinochle牌组和一个常规牌组来强制执行卡实例限制。

牌组应负责确保在创建牌组时没有重复。甲板创建可以有多个构造器用于不同的游戏。

如果这是一种典型的异常情况,并且永远不会发生,那么他们抛出异常可能是正确的做法。首先,我会尽你所能阻止这种情况发生。

抛出ArgumentException将是一个可接受的解决方案。从MSDN:

当调用方法且传递的参数中至少有一个不符合被调用方法的参数规范时,将引发ArgumentException


当然,您必须在代码的更高层捕获异常,并对其进行适当处理。

我想我理解您的意图

你可以考虑的一件事是防止这种情况发生。我会有一个手工工厂,我可以调用createHand2,其中2是要处理的卡数

在createHand内,你给自己发一张牌,从52张牌堆中取出该牌,然后随机选择另一张牌。这样你就可以有啊广告,啊空调,啊As等等。下次你打电话给createHand的时候,甲板会再次装满

在这个例子中,有一些明显的事情我忽略了,比如如果我发53张牌会发生什么?我会留给你去弄清楚的。这不是线程安全的。而且,Shuffle并不是真正的Shuffle。在随机洗牌中,你可以做的一件事是随机化这些牌,然后换掉DealCard,从列表的顶部挑出这张牌

范例


如果牌组对象将相同的牌传递给单个手部对象,这意味着该过程的状态无效。手部对象应使用带密钥的集合来存储卡,如果向集合中添加了重复密钥,则集合本身将为您抛出异常。所以要回答这个问题,不要在Hand类中处理错误。允许它在层次结构中冒泡。

我的建议是创建一个异常结构,您可以在其中以更清晰的方式识别错误,以便能够处理它

例如,如果您正在创建一个可能具有不同业务规则的游戏,则大多数业务规则异常都应该从基本GameRuleException继承。在本例中,在您的场景中,我将创建一个特定的异常,比如继承GameRuleException的HandCardException

拥有这种层次结构的重要性在于,当您捕获异常时,您可以确保错误来自游戏规则,而不是连接问题,例如

请参阅下面的示例-注意,我没有测试代码,它只是为了演示

public class GameRuleException : Exception
{

    public GameException(string message) : base(message)
    {
    }
}

public class HandCardException : GameRuleException
{

    public HandCardException(string message) : base(message)
    {
    }
}

public class Card
{
    public int r;

    public char s;
    public Card(int rank, char suit)
    {
        r = rank;
        s = suit;
        if (rank > 13 || rank < 1) {
            throw new GameRuleException("The card rank must be between 1 and 13");
        }
    }
}

public class Hand
{
    public Card c1;

    public Card c2;
    public Hand(Card one, Card two)
    {
        //Basic validation

        if (one == null || two == null) {
            throw new HandCardException("Each hand needs at least two cards");
        }

        if (one == two) {
            throw new HandCardException("Repeated cards are found.");
        }

        //Allows creating the instance

        c1 = one;
        c2 = two;

    }
}

这只是一个示例,说明了如何使用自定义异常来更恰当地处理它们

你是如何产生这些手的?也许它们应该来自52张有效的牌组,这样错误就不会发生。你可以同时激活不同的手的组合,比如说啊Ad,啊Ac,啊As。同一个组合不可能有两次。在这个特定的案例中,RedDeckwins:当然,但是Hand类的用户仍然可以做一些愚蠢的事情,比如为两个参数传递相同的卡实例。这是一个有效的观点,我不是从Ash提供某种卡/卡库的角度来考虑的。在工厂中存储卡的最佳方式是什么?在列表中?我认为处理这个异常是不合法的。捕获ArgumentException是一种代码气味。如果你抛出了无效的参数,为什么你要用catch来解决这个问题,而不是传递有效的参数?如果参数无效,我会说抛出异常,但不要捕获它。ArgumentException应该只用于无效参数。例如,钻石皇后是该方法的有效参数。@克里斯·盖斯勒:钻石皇后和钻石皇后不是有效参数。方法:AddCardsCard卡;只要我传递一张有效的卡片,它就是一个有效的论点。然而,如果我叫hand.addcardsnll;或hand.addcards新卡;这些卡是无效的。如果添加有效卡本身引发异常,系统应在Hand类之外处理该异常。@Chris:AddCardsnew card'Q','D';AddCardsnew Card'Q','D':传递的两个实例都是有效的卡,但是,如果不希望重复,第二个实例是无效的参数。传递的参数不符合被调用方法的参数规范。只要你传递一张有效的卡片,它就不是一个有效的参数。是的
只要你满足方法的参数说明,这是一个有效的参数。只是我回答中的一个注意事项,我讨论的是如何处理异常,而不是建议的示例的设计。很抱歉造成混淆,我的第一个想法是检查重复项并抛出异常,但这会被认为是防御性的编码。我同意牌组应该确保没有重复,而且这很容易做到,但这并不意味着同一张独特的牌不能多次传递给一只手。
public interface Hand
{
    Card C1
    {
        get;
    }

    Card C2
    {
        get;
    }
}

public interface Dealer
{
     Hand DealHand();
}

public class SpecialDealer : Dealer
{
    private Deck mDeck;

    private class HandImpl : Hand
    {
        private Card mC1;
        private Card mC2;

        public Card C1
        {
            get
            {
                return mC1;
            }
        }

        public Card C2
        {
            get
            {
                return mC2;
            }
        }

        public HandImpl(Card c1, Card c2)
        {
            mC1 = c1;
            mC2 = c2;
        }

        public override string ToString()
        {
            return C1 + " " + C2;
        }
    }

    public SpecialDealer(Deck deck)
    {
        mDeck = deck;
    }

    public Hand DealHand()
    {
        return new HandImpl(mDeck.DealCard(), mDeck.DealCard());
    }
}
public class GameRuleException : Exception
{

    public GameException(string message) : base(message)
    {
    }
}

public class HandCardException : GameRuleException
{

    public HandCardException(string message) : base(message)
    {
    }
}

public class Card
{
    public int r;

    public char s;
    public Card(int rank, char suit)
    {
        r = rank;
        s = suit;
        if (rank > 13 || rank < 1) {
            throw new GameRuleException("The card rank must be between 1 and 13");
        }
    }
}

public class Hand
{
    public Card c1;

    public Card c2;
    public Hand(Card one, Card two)
    {
        //Basic validation

        if (one == null || two == null) {
            throw new HandCardException("Each hand needs at least two cards");
        }

        if (one == two) {
            throw new HandCardException("Repeated cards are found.");
        }

        //Allows creating the instance

        c1 = one;
        c2 = two;

    }
}
try {
    Hand hand = new Hand(card1, card2);
} catch (GameRuleException ex) {
    //Handle the error by showing the error in a label ... 
    ErrorLabel.Text = ex.message;
} catch (Exception ex) {
    //Any other exception will log
    //Trace.Error(ex)
    //And maybe throw back the exception... ?
    //Throw
}