【问题标题】:c# how to code a class method that can be called on the instance of the classc#如何编写可以在类的实例上调用的类方法
【发布时间】:2018-12-12 04:53:45
【问题描述】:

使用 c# .net 4.7.1 我有一个名为 Deck 的类,代码如下:

public class Deck
{
    public Card[] DeckOfCards { get; private set; } = new Card[56];        

    public Deck()
    {
        DeckOfCards = NewDeck();
    }

    private Card[] NewDeck()
    {
        Card[] newDeck = new Card[56];
        ....
        return newDeck;
    }
}

我想在Deck 中声明一个名为Shuffle 的类方法,我可以在我创建的Deck 实例上调用它。以下是我在程序中描绘的 Main 方法的样子:

class program
{
    static void Main(string[] args)
    {
        Deck WorkingDeck = new Deck();
        WorkingDeck.DeckOfCards.Shuffle();
        ....
    }
}

到目前为止,这是我对类方法 Shuffle 的所有内容:

    public Card[] Shuffle(this Card[] DeckToShuffle)
    {
        Random rnd = new Random();
        Card[] ShuffledDeck = DeckToShuffle.OrderBy(x => rnd.Next()).ToArray();
        return ShuffledDeck;
    }

但这要求我在方法调用中传递Card[]。我想要使​​用WorkingDeck.DeckOfCards 作为被洗牌的Deck 的方法。有人可以指出我能够做到这一点的正确方向吗?提前致谢。

【问题讨论】:

  • 你不需要暴露DeckOfCards。你有一个非静态类Deck。让它代表一副纸牌。有一个构造函数,它带有一个关于它是否应该包含小丑的标志。有一个方法叫Shuffle,另一个叫TakeTopCard。另一个称为Deal,带有两个参数cardsPerHandhands。但不要直接暴露你的纸牌存储。这样,如果您认为 List<Card> 比数组更有意义,您可以更改实现而不更改卡片组的公共抽象。

标签: c# method-call


【解决方案1】:

在这种特殊情况下,扩展方法将是一个很好的解决方案。

public static class Extensions
{
    public static void Shuffle(this IEnumerable<Card> source)
    {
        // Body of Shuffle
    }
}

这将帮助您根据需要调用 shuffle

Deck WorkingDeck = new Deck();
WorkingDeck.DeckOfCards.Shuffle();

【讨论】:

  • 正是我想要的。我感觉this 关键字是解决方案的一部分,但这是我第一次听说扩展方法。接受为答案并投票赞成。非常感谢。
  • 我可能说得太早了。您的回答确实允许我像这样调用Shuffle 方法WorkingDeck.DeckOfCards.Shuffle() 并且WorkingDeck.DeckOfCards 的值确实被传递给扩展方法但是WorkingDeck.DeckOfCards 的值在Shuffle 之后在我的主要方法中没有改变被调用。缺少一些东西,因此新的“ShuffledDeck”没有被传递回主方法。你能进一步帮助我吗?
  • 好的,我玩弄了一下,发现为了使值反映在我的主要方法中,我必须声明另一个 Card[] 并将该值设置为等于 WorkingDeck.DeckOfCards.Shuffle(); 所以我的main 方法现在有这个:Card[] ShuffledDeck = WorkingDeck.DeckOfCards.Shuffle(); 我认为没有办法直接更改WorkingDeck.DeckOfCards 的值,所以必须像我一样声明一个新的Card[]。如果有人知道我如何直接更改 WorkingDeck.DeckOfCards 的值,我很想听听。
【解决方案2】:

首先,您可以将Deck 类简化如下:

public class Deck {

    public Card[] DeckOfCards { get; private set; } = NewDeck();

    private static Card[] NewDeck() {
        Card[] newDeck = new Card[56];
        ....
        return newDeck;
    }
}

如果你想让Shuffle改变你Deck中卡片的顺序,你可以写一个扩展方法,像这样:

static class DeckExtensions {

    public static void Shuffle(this deck)
    {
        Random rnd = new Random();
        deck.DeckOfCards = deck.DeckOfCards.OrderBy(x => rnd.Next()).ToArray();
    }

}

【讨论】:

  • 可以是Deck的实例方法,就像安德鲁建议的那样
  • @EhsanSajjad 绝对。不过,在问题的标题中,作者要求提供一个类方法。
  • “可以在类的实例上调用的类方法”...想一想,也许这是对扩展方法的恰当描述:-)
  • @dasbinkenlight ,非常感谢您的建议和回答。已经接受了第一个答案作为已接受的答案,但也对此投了赞成票。再次感谢。
  • @AndrewShepherd 我最喜欢的这种描述一直是“椭圆是一个内接不等边正方形的圆”:-)
【解决方案3】:

DeckOfCards 属性是该类的成员。类上的方法可以自动访问其成员(隐式或通过 this 关键字)。

public class Deck
{
    public Card[] DeckOfCards { get; private set; };        

    public Deck()
    {
        this.DeckOfCards = NewDeck();
    }

    static Card[] NewDeck()
    {
        Card[] newDeck = new Card[56];
        ....
        return newDeck;
    }

    public void Shuffle()
    {
        Random rnd = new Random();
        Card[] shuffledDeck = this.DeckOfCards.OrderBy(x => rnd.Next()).ToArray();
        this.DeckOfCards = shuffledDeck;
    }
}

你可以这样调用它:

static void Main(string[] args)
{
    Deck workingDeck = new Deck();
    workingDeck.Shuffle();
    ....
}

此设计将Deck 作为可变对象:Shuffle 更改现有卡片组的顺序,而不是创建不同的卡片组。

顺便说一句,还有更好的洗牌方法可供使用。此处 Google 的术语是“Fisher-Yates 算法”。

【讨论】:

  • 这对我不起作用。首先Shuffle 方法返回Card[],但方法定义说它返回void。修复了我仍然无法像 WorkingDeck.DeckOfCards.Shuffle() 这样调用 Shuffle 方法的问题。如其他两个答案中所述编写扩展类适用于我的情况。不过感谢您的回答。
  • @I_am_Jacks_colon 我已经添加了关于在这种情况下如何调用它的额外部分。我同意扩展方法方法感觉更优雅。
  • 我其实更喜欢这个。我认为在Deck 类定义中包含该方法更干净,我喜欢我可以调用WorkingDeck.Shuffle(),它会更改WorkingDeck.DeckOfCards,而无需声明新的Card[] 并将其分配给洗牌后的值WorkingDeck.DeckOfCards。我不想从 Anu Viswan 那里拿走公认的答案,但这肯定值得一票。这真的正是我想要的。感谢你的回答!!!!注意:Shuffle() 方法仍然需要更改为返回 Card[] 而不是 void ;)
  • @I_am_Jacks_colon:我可以更改签名以返回Card[],或者我可以更改方法实现,使其不返回任何内容。我改了方法实现,感觉还是和封装的设计方式保持一致。
  • 很好,我完全同意。我认为将Shuffle() 的签名更改为返回void,然后更改方法的定义使其不返回Card[] 看起来很棒。
猜你喜欢
  • 2014-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-21
  • 1970-01-01
  • 2010-10-08
  • 2017-03-09
  • 1970-01-01
相关资源
最近更新 更多