读书人

C#学习札记其他

发布时间: 2013-01-04 10:04:16 作者: rapoo

C#学习笔记——其他

运算符重载

C#运算符被定义为使用预定义类型作为操作数来工作。如果面对一个用户定义类型,运算符完全不知道如何处理它。运算符重载运行定义C#运算符操作自定义类型的操作数。

运算符重载只能用于类和结构。

为类或结构重载一个运算符x,可以声明一个名称为operator x的方法并实现它的行为。

一元运算符的重载方法带一个单独的class或struct类型的参数。

二元运算符的重载方法带两个参数,其中至少有一个必须是class或struct类型。

?

运算符重载方法必须被声明为:

带static和public两个修饰符。

类和结构的成员,该类或结构是它的一个操作数。

?

运算符重载的限制:

可重载的一元运算符:+,-,!,~,++,--,true,false

可重载的二元运算符:+,-,*,/,%,&,|,^,<<,>>,==,!=,>,<,>=,<=

?

递增和递减运算符是可重载的。但和预定义转换不同,重载运算符的前置和后置之前没有区别。

运算符重载不能做如下事情:

创建新运算符。

改变运算符的语法。

重新定义运算符如何让处理预定义类型。

改变运算符的优先级或结合性。

?

例:

?

class LimiterInt{

? ? const int MaxValue=100;

const int MinValue=0;

public static LimiterInt operator -(LimiterInt x)

{

? ?LimiterInt li=new LimiterInt();

li.TheValue=0;

return li;

}

public static LimiterInt operator -(LimiterInt x,LimiterInt y)

{

? ?LimiterInt li=new LimiterInt();

li.TheValue=x.TheValue-y.TheValue;

return li;

}

public static LimiterInt operator +(LimiterInt x,LimiterInt y)

{

? ?LimiterInt li=new LimiterInt();

li.TheValue=x.TheValue+y.TheValue;

return li;

}

?

? ? ? ? private int _TheValue=0;

public int TheValue

{

? ?get{return _TheValue;}

set

{

? ?if(value<MinValue)

? ?_TheValue=0;

else

? ?_TheValue=value>MaxValue?MaxValue:true;

}

}

?

}

?

?

class Program

{

? ? static void main(){

? ? ? ? LimiterInt li1=new LimiterInt();

LimiterInt li2=new LimiterInt();

LimiterInt li3=new LimiterInt();

li1.TheValue=10;li2.TheValue=26;

li3=-li;

Console.WriteLine("-{0}={1}",li1.TheValue,li3.TheValue);

li3=li2-li1;

Console.WriteLine("{0}-{1}={2}",li2.TheValue,li1.TheValue,li3.TheValue);

li3=li2+li1;

Console.WriteLine("{0}+{1}={2}",li2.TheValue,li1.TheValue,li3.TheValue);

? ? }

}





typeof运算符typeof运算符返回作为它的参数的任何类型的System.Type对象。通过这个对象,可以得到类型的特征。(对任何已知类型,只要一个System.Type对象。)typeof运算符是一元运算符。例:Type是System命名空间中的一个类:Type t=typeof(SomeClass)
不能重载typeof。
例:使用typeof运算符以获取类的信息,并打印出它的公有字段和方法的名称。using System.Reflection;
class SomeClass{? ? public int Field1;public int Field2;public void Method1(){}public int Method2(){}}
class Program{? ? static void Main(){ ? ?Type t=typeof(SomeClass); ? ?FieldInfo[] fi=t.GetFields();MethodInfo[] mi=t.GetMethods();foreach(FieldInfo f in fi) ? ?Console.WriteLine("Field : {0}",f.Name);foreach(MethodInfo m in mi) ? ?Console.WriteLine("Method : {0}",m.Name);}}

typeof运算符还被GetType方法调用,该方法对每个类型的每个对象都有效。class SomeClass{? ? ...}
class Program{? ? static void Main()? ? {? ? ? ? SomeClass s=new SomeClass();? ? ? ? Console.WriteLine("Type s : {0}",s.GetType().Name);? ? }}




using语句

?

public class SquareWidget

{...}

public class CircleWidget

{

??? public double Radius = 0;

??? public double Area

??? {

??????? get{...}

??? }

}

??? 因为两个库都含有名称为SquareWidget的类,当你试图编译程序MyWidgets对,编译器产生一条错误消息,因为它不知道使用类SquareWidget的哪个版本。此即命名冲突。

?

?

命名空间

??? 在MyWidgets示例中,由于你有源代码,你能通过在SuperLib源代码或UltraLib源代码中仅仅?? 改变SquareWidget类的名称来解决命名冲突。但是,如果这些类是由不同的公司开发的,而且你还不能拥有源代码会怎么样呢?假设SuperLib由一个名称为MyCorp的公司生产,UltraLib由ABCCorp公司生产。在这种情况下,如果你使用了任何有冲突的类或类型,你将不能把这两个库放在一起使用。

??? 你能想象得出,在你做开发的机器上含有数打不同的公司生产的程序集,很可能有一定数量的类名重复。如果你不能把两个程序集用在一个程序中,仅仅因为它们碰巧有共同的类型名,这将是一种耻辱。命名空间特征须帮助你避免这个问题。

??? 命名空间把一组类型分组在一起并给它们一个名称,称为命名空间名称。命名空间名称应该描述命名空间的内容并和其他命名空间名称相区别。

??? 下面展示了声明。个命名空间的语法。声明在大括号中间的所有类和其他类型的名称都是命名空间的成员。

?

? 关键字??? 命名空间名

namespace SimpleNamespace

(

? TypeOeclarations

}

?

??? 现在假设在MyCorp公司的程序员改变该源代码如下面的示例所示。它现在有一个环绕类声明的命名空间了。注意关于命名空间名称的两个有趣的事情:

??? 命名空间可以包含前缀。

??? 公司名称在命名空间名称的开始。

namespace MyCorp.SuperLib

{

?? public class SquareWidget

?? {

??????? public double SideLength=o;

??????? public double Area

??????? {

??????????? get { retum SideLength *SideLength;}

????????????? }

?????? }

}

?

??? 当MyCorp公司运给你更新的程序集时,你可以通过修改你的MyWidgets程序如下面所示来使用它。注意,不仅使用类名(由于它在两个类库之间不明确)和使用命名空间名称做类名的前缀,并使用句点把它们隔开。带有命名空间名称和类名的整体字符串被称为完全限定名。

??? class WidgetsProgram

??? {

?????? ??? MyCorp.SuperLib.SquareWidget sq=newMyCorp.SuperLib.SquareWidget();

?????????????

????????????? CircleWidget circle =new CircleWidget();

????????????? ...

?????? }

?

现在你在代码中显示指示了SquareWidget的SuperLib版本,编译器不会再区分类的问题了。

?

?

?

?

?

命名空间名称

如你所见,命名空间的名称可以包含创建该程序集的公司的名称。除了标识公司以外,该名称还用于帮助程序员获得定义在命名空间内的类型的种类的快速印象。

??? 关于命名空问名称的一些要点如下:

??? 命名空间名称可以是任何有效标识符。

??? 命名空间名称可以包括句点符号,用于把类型组织成层次。

??? 例如,表列出了一些在.NET BCL中的命名空间的名称。

??????

?????? 下面是建议的命名空问命名指南:

使用公司名开始命名空间名称。

在公司名之后跟着技术名称。

不要把命名空间命名为与类或类型相同的名称。

?

例如,Acme Widget公司的软件开发部门在下面三个命名空间中开发软件,如下面的代码所示:

AcmeWidgets.SuperWidget

AcmeWidgets.Media

AcmeWidgets .Games

namespace AcmeWidgets.SuperWidget.SPDComponent

{

??? class SPDBase...

?????? ...

}

?

?

命名空间的补充

??? 关于命名空间,有其他几个要点应该知道:

??????? 在命名空间内,每个类型名必须有别于所有其他类型。

??????? 命名空间内的类型称为命名空间的成员。

??????? 一个源文件可以包含任意数日的命名空间声明,可以顺序也可以嵌套。

?????????????

?

注意,尽管命名空问内含有几个共有的类名,它们被它们的命名空间名称区分开来。

?

??? .NET框架BCL提供了数千个已定义的类和类型以供在生成你的程序时选择。为了帮助组织这组有用的功能,相关功能的类型被声明在相同的命名空间里。BCL使用超过100个命名空间来组织它的类型。

?

?

?

命名空间跨文件延伸

命名空间不是封闭的。这意味着可以在该源文件的后面或另一个源文件中再次声明它,以对它增加更多的类型声明。

?

?

嵌套命名空间

??? 一个命名空间可以是另一个命名空间的成员。这个成员被称为嵌套的命名空间。嵌套命名空间允许你创建类型的概念层次。

??? 虽然嵌套的命名空间是外层命名空间的成员,但它的成员不是外层命名空间的成员。人们最初有对嵌套的命名空间的误解是既然嵌套的命名空间在外层命名空间内部,那么嵌套命名空间的成员必须是外层命名空间昀子集。这是不对的,这些命名空间是分离的。

??? 有两种方法声明一个嵌套的命名空间,如下所示。

?

原文嵌套:可以把命名空间的声明放在一个封装的命名空间声明体内部,从而创建一个嵌套的命名空间。

namespace MyNamespace

{

??? class MyClass{...}

?????? namespace OtherNs

?????? {

?????? ??? class OtherClass{...}

?????? }

}

分离的声明:也可以为嵌套命名空间创建分离的声明,但必须在声明中使用它的完全限定名称。

namespace MyNamespace

{

??? class MyClass{...}

}

namespace MyNamespace.OtherNs

{

??? class OtherClass{...}

}

?

?

using指令

??? 完全限定名可能相当长,在代码中通篇使用它们会变得十分乏味。然而,有两个编译指令,可以使你避免不得不使用完全限定名:using命名空间指令和using别名指令。

??? 关于using指令词的两个要点如下:

??????? 它们必须放在源文件的顶端,在任何类型声明之前。

??????? 它们应用于当茼源文件中的所有命名空间。

?????????????

using命名空间指令

??? using命名空间指令通知编译器你将要使用来自某个指定命名空间的类型。然后你可以继续,并使用简单类名而小必全路径修饰它们。

?

当编译器遇到一个不在当前命名空问的名称时,它检查在using命名空间指令中给出的命名空间列表,并把该未知名称加到列表中的第一个命名空间后面。如果结果完全限定名称匹配了这个程序集或引用程序集中的一个类,编译器将使用那个类。如果不匹配,那么它试验列表中下一个命名空间。

??? using命名空间指令由关键字using跟着一个命名空间标识符组成。

?

关键宇 命名空间的名称

using System;

?

??? WriteLine方泫是类Console的成员,在System命名空间中。

??? 例如,下面的代码在第一行使用using命名空间指令以描述该代码使用来自system命名空问

类或其他类型。

using System;//命名空间指令

...

System.Console.WriteLine("This is text l");//使用完全限定名称

Console.WriteLine("This is text 2");//使用指令

?

?

using别名指令

??? using别名指令允许起一个别名给:

??? 命名空间

??? 命名空间内的一个类型

??? 例如,下面的代码展示了两个using别名指令的使用。第一个指令告诉编译器标识符Syst是命名空间system的别名。第二个指令表明标识符SC是类System.Console的别名。

??? 关键宇? 别名?? 命名空间

??? using Syst = System;

??? using SC = System.Console;

??? 关键宇 别名???? 类

下面的代码使用这些别名。在Main中三行代码都调用System.Console.WriteLine方法。

Main的第一条语句使用命名空间(System)的别名。

第二条语句使用该方法的完全限定名。

第三条语句使用类(Console)的别名。

using Syst = System;??? //using别名指令

using SC = System.Console;???//using别名指令

?

namespace MyNamespace

{

??? class SomeClass

??? {

??????? static void Main()

??????? {

???????????Syst.Console.WriteLine("Using the namespace alias.");//命名空间的别名

???????????System.Console.HriteLine("Using fully qualified name.");

??????????? SC.HriteLine("Usingthe type alias");? //类的别名

??????? }

??? }

}

?

?

程序集的结构

??? 程序集不包含本地机器代码,而是公共中间语言代码。它还包含实时编译器(JIT)在运行时转换CIL到本机代码所需的一切,包括对它所引用的其他程序集的引用。

程序集的文件扩展名通常为.exe或.dll。

??? 大部分程序集由一个单独的文件构成。

??? 程序集的清单包含:

????????????? 程序集名称标识符。

????????????? 组成程序集的文件列表。

????????????? 一个指示程序集中内容在哪里的地图。

????????????? 关于引用的其他程序集的信息。

??? 类型元数据部分包含该程序集中定义的所有类型的信息。这些信息包含关于每个类型要知道的所有事情。

??? CIL部分包含程序集的所有中间代码。

??? 资源部分是可选的,但可以包含图形和语言资源。












?

读书人网 >C#

热点推荐