(原创)c#学习笔记10--定义类成员06--示例应用程序02--编写类库

10.6.2  编写类库

  类和枚举都包含在一个类库项目 Ch10CardLib 中。这个项目将包含 4 个.cs 文件,Card.cs 包含Card类的定义,Deck.cs包含Deck类的定义,Suit.cs和Rank.cs文件包含枚举。

  1. \Chapter10目录中创建一个新类库项目Ch10CardLib。从项目中删除Class1.cs。

  2. 添加:Suit.cs和Rank.cs文件,如下所示修改:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ch10CardLib
{
    public enum Rank
    {
        Ace = 1,
        Deuce,
        Three,
        Four,
        Five,
        Six,
        Seven,
        Eight,
        Nine,
        Ten,
        Jack,
        Queen,
        King,
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ch10CardLib
{
    public enum Suit
    {
        Club,
        Diamond,
        Heart,
        Spade,
    }
}

  3. 添加Card类,代码如下:

public class Card {
    public readonly Suit suit;
    public readonly Rank rank;

    public Card( Suit newSuit, Rank newRank ) {
        suit = newSuit;
        rank = newRank;
    }

    private Card() {

    }

    public override string ToString() {
        return "The " + rank + " of " + suit + "s";
    }
}

  重写的ToString()方法将已存储的枚举值的字符串表示写入到返回的字符串中, 非默认的构造函数初始化suit和rank字段的值。

  3. 添加Deck类

    Deck类需要使用类图定义的如下成员:

      Card[]类型的私有字段cards。

      公共的默认构造函数。

      公共方法GetCard(),它带有一个int参数cardNum,并返回一个Card类型的对象。

      公共方法Shuffle(),它不带参数,返回void。

  代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ch10CardLib
{
    public class Deck
    {
        private Card[] cards;
        public Deck()
        {
            cards = new Card[52];
            for (int suitVal = 0; suitVal < 4; ++suitVal)
            {
                for (int rankVal = 1; rankVal < 14; ++rankVal)
                {
                    cards[suitVal * 13 + rankVal - 1] = new Card((Suit)suitVal, (Rank)rankVal);
                }
            }
        }

        public Card GetCard(int cardNum)
        {
            if (cardNum >= 0 && cardNum <= 51)
            {
                return cards[cardNum];
            }
            else
            {
                throw (new System.ArgumentOutOfRangeException("cardNum", cardNum, "Value must be between 0 and 51."));
            }
        }

        public void Shuffle()
        {
            Card[] newDeck = new Card[52];
            bool[] assigned = new bool[52];
            Random sourceGen = new Random();
            for (int i = 0; i < 52; ++i)
            {
                int destCard = 0;
                bool foundCard = false;
                while (false == foundCard)
                {
                    destCard = sourceGen.Next(52);
                    if (false == assigned[destCard])
                    {
                        foundCard = true;
                    }
                }
                assigned[destCard] = true;
                newDeck[destCard] = cards[i];
            }
            newDeck.CopyTo(cards, 0);
        }
    }
}

  Shuffle()方法。这个方法创建一个临时的扑克牌数组,并把扑克牌从现有的cards数组随机复制到这个数组中。这个函数的主体是一个从 0~51 的循环,在每次循环时,都会使用.NET Framework中的System.Random类的实例生成一个0~51之间的随机数。进行了实例化后,这个类的对象使用方法Next(X)生成一个介于0~X之间的随机数。有了一个随机数后,就可以使用它作为临时数组中Card对象的索引,以便复制cards数组中的扑克牌。

  为了记录已赋值的扑克牌,我们还有一个bool变量的数组,在复制每张牌时,把该数组中的值指定为 true。在生成随机数时,检查这个数组,看看是否已经把一张牌复制到临时数组中由随机数指定的位置上了,如果已经复制好了,就将生成另一个随机数。

  这不是完成该任务的最高效的方式,因为生成的许多随机数都可能找不到空位置以复制扑克牌。但是,它仍能完成任务,而且很简单,因为C#代码的执行速度很快,我们几乎觉察不到延迟。

  这个方法的最后一行使用System.Array类的CopyTo()方法(在创建数组时使用),把newDeck中的每张扑克牌复制回 cards 中。也就是说,我们使用同一个 cards 对象中的同一组 Card 对象,而不是创建新的实例。如果改用cards = newDeck,就会用另一个对象替代cards引用的对象实例。如果其他地方的代码仍保留对原cards实例的引用,就会出问题——不会洗牌。

  至此,就完成了类库代码。

时间: 2024-10-26 23:25:37

(原创)c#学习笔记10--定义类成员06--示例应用程序02--编写类库的相关文章

(原创)c#学习笔记10--定义类成员06--示例应用程序03--类库的客户应用程序

10.6.3  类库的客户应用程序 新项目命名为Ch10CardClient.添加一个对类库项目Ch10CardLib的引用.代码如下: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Ch10CardLib; namespace Ch01CardClient { class Program { sta

(原创)c#学习笔记10--定义类成员02--类成员的其他议题02--调用重写或隐藏的基类方法

10.2.2  调用重写或隐藏的基类方法 无论是重写成员还是隐藏成员,都可以在派生类的内部访问基类成员.这在许多情况下都是很有用的,例如: 要对派生类的用户隐藏继承的公共成员,但仍能在类中访问其功能. 要给继承的虚拟成员添加实现代码,而不是简单地用重写的新执行代码替换它. 为此,可以使用 base 关键字,它表示包含在派生类中的基类的实现代码(在控制构造函数时,其用法是类似的,如第9所述),例如: public class MyBaseClass { public virtual void Do

(原创)c#学习笔记10--定义类成员01--成员定义05--重构成员

10.1.5  重构成员 在添加属性时有一项很方便的技术,可以从字段中生成属性在添加属性时有一项很方便的技术,可以从字段中生成属,下面是一个重构(refactoring)的示例,“重构”表示使用工具修改代码,而不是手工修改.为此,只需右击类图中的某个成员,或者在代码视图中右击某个成员即可. 例如,如果MyClass类包含如下字段: public string myString; 右击该字段,选择“重构 ? 封装字段”(Refactor ?Encapsulate Field),就会打开如图10-7

(原创)c#学习笔记10--定义类成员01--成员定义03--定义属性

10.1.3  定义属性 属性定义方式与字段类似,但包含的内容比多.如前所述,属性涉及的内容比字段多,是因为它们在修改状态前还可以执行一些额外的操作.实际上,它们可能并不修改状态.属性拥有两个类似于函数的块,一个块用于获取属性的值,另一个块用于设置属性的值. 这两个块也称为访问器,分别用get和set关键字来定义,可以用于控制对属性的访问级别.可以忽略其中的一个块来创建只读或只写属性(忽略get块创建只写属性,忽略set块创建只读属性).当然,这仅适用于外部代码,因为类中的其他代码可以访问这些代

(原创)c#学习笔记10--定义类成员05--部分方法定义

10.5  部分方法定义 部分类也可以定义部分方法.部分方法在部分类中定义,但没有方法体,在另一个部分类中包含实现代码.在这两个部分类中,都要使用partial关键字. public partial class MyClass { partial void MyPartialMethod(); } public partial class MyClass { partial void MyPartialMethod() { // Method implementation } } 部分方法也可以

(原创)c#学习笔记09--定义类01--c#中的类定义

第九章 定义类 本章内容: ●  如何在C#中定义类和接口 ●  如何使用控制可访问性和继承的关键字 ●  System.Object类及其在类定义中的作用 ●  如何使用VS和VCE提供的一些帮助工具 ●  如何定义类库 ●  接口和抽象类的异同 ●  结构类型的更多内容 ●  复制对象的一些重要信息 9.1  C#中的类定义 C#使用class关键字来定义类: class MyClass { // Class members. } 默认情况下,类声明为内部的,即只有当前项目中的代码才能访问它

Python 学习笔记 - 面向对象(类成员)

上一篇学习了Python面向对象的3大特性,封装,继承和多态,这一篇继续学习类成员,包括字段,方法,属性以及他们的修饰符. 1.字段 字段分为静态字段和普通字段.静态字段属于类,而普通字段属于对象,因此静态字段在内存中只保存一份,而普通字段在每个对象中都保存了一份.定义的时候静态字段定义在类的范围里面,而普通字段定义在方法里面. 例如: >>> class Foo:     # 字段(静态字段)     CC = 123     def __init__(self):         #

(原创)c#学习笔记09--定义类05--类库项目

9.5  类库项目 除了在项目中把类放在不同的文件中之外,还可以把它们放在完全不同的项目中.如果一个项目什么都不包含,只包含类(以及其他相关的类型定义,但没有入口点),该项目就称为类库. 类库项目编译为.dll 程序集,在其他项目中添加对类库项目的引用,就可以访问它的内容(这可以是同一个解决方案的一部分,但这不是必须的).这将扩展对象提供的封装性,因为类库可以进行修改和更新,而不会影响使用它们的其他项目.这意味着,您可以方便地升级类提供的服务(这会影响多个用户应用程序). 下面看一个类库项目的示

(原创)c#学习笔记09--定义类06--接口和抽象类

9.6  接口和抽象类 抽象类和接口都包含可以由派生类继承的成员.接口和抽象类都不能直接实例化,但可以声明这些类型的变量.如果这样做,就可以使用多态性把继承这两种类型的对象指定给它们的变量.接着通过这些变量来使用这些类型的成员,但不能直接访问派生对象的其他成员. 下面看看它们的区别.派生类只能继承一个基类,即只能直接继承一个抽象类(但可以用一个继承链包含多个抽象类).相反,类可以使用任意多个接口.但这不会产生太大的区别——这两种情况取得的效果是类似的.只是采用接口的方式略有不同. 抽象类可以拥有