2004年03月20日

循环变量由类型和标识符声明,且表达式与收集相对应。循环变量代表循环正在为之运行的收集元素。不能赋一个新值给循环变量,也不能把它当作ref 或out 参数。这样引用在内含语句中被执行的代码。


类支持foreach 语句,类必须支持具有GetEnumerator()名字的方法,而且由其所返回的结构、类或者接口必须具有public方法MoveNext() 和public 属性Current

abstract——说明一个方法或存取标志不能含有一个实现。它们都是隐式虚拟,且在继承类中,必须提供override关键字。
const——这个修饰符应用于域成员或局部变量。在编译时常量表达式被求值,所以,它不能包含变量的引用。
event ——定义一个域成员或属性作为类型事件。用于捆绑客户代码到类的事件。
extern——告诉编译器方法实际上由外部实现。
override——用于改写任何基类中被定义为virtual的方法和存取标志。要改写的名字和基类的方法必须一致。
readonly——一个使用 readonly修饰符的域成员只能在它的声明或者在包含它的类的构造函数中被更改。


static——被声明为static的成员属于类,而不属于类的实例。可以用static 于域成员、方法、属性、操作符甚至构造函数。
virtual——说明方法或存取标志可以被继承类改写。

abstract——关于抽象类的重要一点就是它不能被实例化。只有不是抽象的派生类才能被实例化。派生类必须实现抽象基类的所有抽象成员。不能给抽象类使用sealed 修饰符。
sealed——密封类不能被继承。使用该修饰符防止意外的继承,在.NET框架中的类用到这个修饰符。


using System;
 
abstract class AbstractClass
{
    abstract public void MyMethod();
}
 
sealed class DerivedClass:AbstractClass
{
    public override void MyMethod()
    {
        Console.WriteLine(“sealed class”);
    }
}


public class TestApp
{
    public static void Main()
    {
        DerivedClass dc = new DerivedClass();
        dc.MyMethod();
    }
}

把客户代码关联到类通知的办法——使用事件


using System;


// 向前声明
public delegate void EventHandler(string strText);


class EventSource
{
    public event EventHandler TextOut;


    public void TriggerEvent()
    {
        if (null != TextOut) TextOut(“Event triggered”);
    }
}


class TestApp
{
    public static void Main()
    {
        EventSource evsrc = new EventSource();


        evsrc.TextOut += new EventHandler(CatchEvent);
        evsrc.TriggerEvent();


        evsrc.TextOut -= new EventHandler(CatchEvent);
        evsrc.TriggerEvent();


        TestApp theApp = new TestApp();
        evsrc.TextOut += new EventHandler(theApp.InstanceCatch);
        evsrc.TriggerEvent();
    }


    public static void CatchEvent(string strText)
    {
        Console.WriteLine(strText);
    }


    public void InstanceCatch(string strText)
    {
        Console.WriteLine(“Instance ” + strText);
    }
}


EventSource 被实例化,而静态方法CatchEvent被预关联上了 TextOut事件:
evsrc.TextOut += new EventHandler(CatchEvent);
从现在起,当事件被触发时,该方法被调用。如果对事件不再感兴趣,简单地取消关联:
evsrc.TextOut -= new EventHandler(CatchEvent);

有两种途径揭示类的命名属性——通过域成员或者通过属性。前者是作为具有公共访问性的成员变量而被实现的;后者并不直接回应存储位置,只是通过存取标志(accessors)被访问。


当你想读出或写入属性的值时,存取标志限定了被实现的语句。用于读出属性的值的存取标志记为关键字get,而要修改属性的值的读写符标志记为set


using System;


public class House
{
    private int m_nSqFeet;


    public int SquareFeet
    {
        get { return m_nSqFeet; }
        set { m_nSqFeet = value; }
    }
}


class TestApp
{
    public static void Main()
    {
        House myHouse = new House();
        myHouse.SquareFeet = 250;
        Console.WriteLine(myHouse.SquareFeet);
    }
}


除了能够隐藏实现细节外,还可自由地限定各种操作:
get和set:允许对属性进行读写访问。
get only:只允许读属性的值。
set only:只允许写属性的值。

除此之外,可以获得实现在set标志中有效代码的机会。例如,由于种种原因(或根本没有原因),你就能够拒绝一个新值。

重定义方法的一个不同手段就是要屏蔽基类的方法。当从别人提供的类派生类时,这个功能特别有价值。


具有了修饰符new,你就可以告诉编译器,不必重写派生类或改变使用到派生类的代码,你的方法就能屏蔽新加入的基类方法。


class BaseClass
{
    public void TestMethod()
    {
        Console.WriteLine(“BaseClass::TestMethod”);
    }
}


class DerivedClass:BaseClass
{
    new public void TestMethod()
    {
        Console.WriteLine(“DerivedClass::TestMethod”);
    }
}


使用了附加的new修饰符,编译器就知道你重定义了基类的方法,它应该屏蔽基类方法。但是,如果按以下方式编写:
DerivedClass test = new DerivedClass();
((BaseClass)test).TestMethod();
基类方法的实现就被调用了。这种行为不同于改写方法,后者保证大部分派生方法获得调用。

基类中,virtual 关键字设计方法:
virtual void CanBOverridden()
当从基类派生时,所有你要做的就是在新方法中加入override关键字:
override void CanBOverridden()


调用基类实现


dArea = base.ComputeArea(a,b,c);


 

传递参数可以把它设作一个输出参数。正如该名字所暗示,一个输出参数仅用于从方法传递回一个结果。它和引用参数的另一个区别在于:调用者不必先初始化变量才调用方法


using System;


public class SquareSample
{
    public void CalcSquare(int nSideLength, out int nSquared)
    {
        nSquared = nSideLength * nSideLength;
    }
}


class SquareApp
{
    public static void Main()
    {
        SquareSample sq = new SquareSample();


        int nSquared; // 不必初始化
        sq.CalcSquare(15, out nSquared);
        Console.WriteLine(nSquared.ToString());
    }
}

要传递值并原地修改它(也就是在相同的内存位置),用引用参数就很方便。
void myMethod(ref int nInOut)
因为传递了一个变量给该方法(不仅仅是它的值),变量必须被初始化。否则,编译器会报警。


// class SquareSample
using System;


public class SquareSample
{
    public void CalcSquare(ref int nOne4All)
    {
        nOne4All *= nOne4All;
    }
}
 
class SquareApp
{
    public static void Main()
    {
        SquareSample sq = new SquareSample();
 
        int nSquaredRef = 20;  // 一定要初始化
        sq.CalcSquare(ref nSquaredRef);  // 调用时
        Console.WriteLine(nSquaredRef.ToString());
    }
}

2004年03月19日