yongshi123

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

    声明结构的默认(无参数)构造函数是错误的。总是提供默认构造函数以将结构成员初始化为它们的默认值。在结构中初始化实例字段也是错误的。如果使用 new 运算符创建结构对象,则会创建该结构对象,并调用适当的构造函数。与类不同,结构的实例化可以不使用 new 运算符。如果不使用 new,则在初始化所有字段之前,字段都保持未赋值状态且对象不可用。对于结构,不像类那样存在继承。一个结构不能从另一个结构或类继承,而且不能作为一个类的基。但是,结构从基类 Object 继承。结构可实现接口,其方式同类完全一样。与 C++ 不同,无法使用 struct 关键字声明类。在 C# 中,类与结构在语义上是不同的。结构是值类型,而类是引用类型。
    通过继承,一个类可以用作多种类型:可以用作它自己的类型、任何基类型,或者在实现接口时用作任何接口类型。这称为多态性。无论在派生类和最初声明虚成员的类之间已声明了多少个类,虚成员都将永远为虚成员。如果类 A 声明了一个虚拟成员,类 B 从 A 派生,类 C 从类 B 派生,则类 C 继承该虚拟成员,并且可以选择重写它,而不管类 B 是否为该成员声明了重写。
    派生类可以通过将重写声明为密封的来停止虚拟继承。这需要在类成员声明中将 sealed 关键字放在 override 关键字的前面。例如:
public class C : B
{
    public sealed override void DoWork() { }
}
    接口描述的是可属于任何类或结构的一组相关功能。接口可由方法、属性、事件、索引器或这四种成员类型的任意组合构成。接口不能包含字段。接口成员一定是公共的。接口成员没有显式的写出限制域,接口类也一样。
    若要实现接口成员,类中的对应成员必须是公共的、非静态的,并且与接口成员具有相同的名称和签名。如果两个接口成员执行不同的函数,那么这可能会导致其中一个接口的实现不正确或两个接口的实现都不正确。可以显式地实现接口成员 -- 即创建一个仅通过该接口调用并且特定于该接口的类成员。这是使用接口名称和一个句点命名该类成员来实现的。代码如下:
public class SampleClass : IControl, ISurface
{
    void IControl.Paint()
    {
        System.Console.WriteLine("IControl.Paint");
    }
    void ISurface.Paint()
    {
        System.Console.WriteLine("ISurface.Paint");
    }
}
类成员 IControl.Paint 只能通过 IControl 接口使用,ISurface.Paint 只能通过 ISurface 使用。两个方法实现都是分离的,都不可以直接在类中使用。例如:
SampleClass obj = new SampleClass();
//obj.Paint();  // Compiler error.

IControl c = (IControl)obj;
c.Paint();  // Calls IControl.Paint on SampleClass.

ISurface s = (ISurface)obj;
s.Paint(); // Calls ISurface.Paint on SampleClass.
显式实现还用于解决两个接口分别声明具有相同名称的不同成员(如属性和方法)的情况:
interface ILeft
{
    int P { get;}  //这个是一个属性来的
}
interface IRight
{
    int P();    //这个是一个方法
}
为了同时实现两个接口,类必须对属性 P 和/或方法 P 使用显式实现以避免编译器错误。例如:
class Middle : ILeft, IRight
{
    public int P() { return 0; }
    int ILeft.P { get { return 0; } }
}

    在派生类中,如果不使用 base 关键字来显式调用基类构造函数,则将隐式调用默认构造函数(如果有的话)。如果基类没有提供默认构造函数,派生类必须使用 base 显式调用基构造函数。基类的构造函数在执行构造函数块之前被调用。base 关键字可带参数使用,也可不带参数使用。

    静态构造函数具有以下特点:

静态构造函数既没有访问修饰符,也没有参数。

在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数来初始化类。

无法直接调用静态构造函数。

在程序中,用户无法控制何时执行静态构造函数。

静态构造函数的典型用途是:当类使用日志文件时,将使用这种构造函数向日志文件中写入项。

静态构造函数在为非托管代码创建包装类时也很有用,此时该构造函数可以调用 LoadLibrary 方法。代码如下:
public class Bus
{
    // Static constructor:
    static Bus()
    {
        System.Console.WriteLine("The static constructor invoked.");
    }

    public static void Drive()
    {
        System.Console.WriteLine("The Drive method invoked.");
    }
}

class TestBus
{
    static void Main()
    {
        Bus.Drive();
    }
}

    复制对象一个很好的例子:
class Person
{
    private string name;
    private int age;

    // Copy constructor.
    public Person(Person previousPerson)
    {
        name = previousPerson.name;
        age = previousPerson.age;
    }

    // Instance constructor.
    public Person(string name, int age)
    {
        this.name = name;
        this.age = age;
    }

    // Get accessor.
    public string Details
    {
        get
        {
            return name + " is " + age.ToString();
        }
    }
}

class TestPerson
{
    static void Main()
    {
        // Create a new person object.
        Person person1 = new Person("George", 40);

        // Create another new object, copying person1.
        Person person2 = new Person(person1);
        System.Console.WriteLine(person2.Details);
    }
}

    委托类型是密封的,不能从 Delegate 中派生委托类型,也不可能从中派生自定义类。
委托应用一个不错的代码例子:
// A set of classes for handling a bookstore:
namespace Bookstore
{
    using System.Collections;

    // Describes a book in the book list:
    public struct Book
    {
        public string Title;        // Title of the book.
        public string Author;       // Author of the book.
        public decimal Price;       // Price of the book.
        public bool Paperback;      // Is it paperback?

        public Book(string title, string author, decimal price, bool paperBack)
        {
            Title = title;
            Author = author;
            Price = price;
            Paperback = paperBack;
        }
    }

    // Declare a delegate type for processing a book:
    public delegate void ProcessBookDelegate(Book book);

    // Maintains a book database.
    public class BookDB
    {
        // List of all books in the database:
        ArrayList list = new ArrayList();

        // Add a book to the database:
        public void AddBook(string title, string author, decimal price, bool paperBack)
        {
            list.Add(new Book(title, author, price, paperBack));
        }

        // Call a passed-in delegate on each paperback book to process it:
        public void ProcessPaperbackBooks(ProcessBookDelegate processBook)
        {
            foreach (Book b in list)
            {
                if (b.Paperback)
                    // Calling the delegate:
                    processBook(b);
            }
        }
    }
}


// Using the Bookstore classes:
namespace BookTestClient
{
    using Bookstore;

    // Class to total and average prices of books:
    class PriceTotaller
    {
        int countBooks = 0;
        decimal priceBooks = 0.0m;

        internal void AddBookToTotal(Book book)
        {
            countBooks += 1;
            priceBooks += book.Price;
        }

        internal decimal AveragePrice()
        {
            return priceBooks / countBooks;
        }
    }

    // Class to test the book database:
    class TestBookDB
    {
        // Print the title of the book.
        static void PrintTitle(Book b)
        {
            System.Console.WriteLine("   {0}", b.Title);
        }

        // Execution starts here.
        static void Main()
        {
            BookDB bookDB = new BookDB();

            // Initialize the database with some books:
            AddBooks(bookDB);

            // Print all the titles of paperbacks:
            System.Console.WriteLine("Paperback Book Titles:");

            // Create a new delegate object associated with the static
            // method Test.PrintTitle:
            bookDB.ProcessPaperbackBooks(PrintTitle);

            // Get the average price of a paperback by using
            // a PriceTotaller object:
            PriceTotaller totaller = new PriceTotaller();

            // Create a new delegate object associated with the nonstatic
            // method AddBookToTotal on the object totaller:
            bookDB.ProcessPaperbackBooks(totaller.AddBookToTotal);

            System.Console.WriteLine("Average Paperback Book Price: ${0:#.##}",
                    totaller.AveragePrice());
        }

        // Initialize the book database with some test books:
        static void AddBooks(BookDB bookDB)
        {
            bookDB.AddBook("The C Programming Language", "Brian W. Kernighan and Dennis M. Ritchie", 19.95m, true);
            bookDB.AddBook("The Unicode Standard 2.0", "The Unicode Consortium", 39.95m, true);
            bookDB.AddBook("The MS-DOS Encyclopedia", "Ray Duncan", 129.95m, false);
            bookDB.AddBook("Dogbert's Clues for the Clueless", "Scott Adams", 12.00m, true);
        }
    }
}

    迭代器是一种方法、get 访问器或运算符,它通过使用 yield 关键字对数组或集合类执行自定义迭代。yield 返回语句会导致源序列中的元素在访问源序列中的下一个元素之前立即返回给调用方。
    迭代器是可以返回相同类型的值的有序序列的一段代码。

迭代器可用作方法、运算符或 get 访问器的代码体。

迭代器代码使用 yield return 语句依次返回每个元素。yield break 将终止迭代。

可以在类中实现多个迭代器。每个迭代器都必须像任何类成员一样有唯一的名称,并且可以在 foreach 语句中被客户端代码调用,如下所示:foreach(int x in SampleClass.Iterator2){}。

迭代器的返回类型必须为 IEnumerable、IEnumerator、IEnumerable<(Of <(T>)>) 或 IEnumerator<(Of <(T>)>)。

迭代器是 LINQ 查询中延迟执行行为的基础。

yield 关键字用于指定返回的一个或多个值。到达 yield return 语句时,会保存当前位置。下次调用迭代器时将从此位置重新开始执行。

posted on 2008-12-15 14:52  yongshi123  阅读(114)  评论(0)    收藏  举报