标签:冗余 abc 签名 程序代码 赋值 dde 成员 关联 strong
通过继承我们可以定义一个新类,新类纳入一个已经声明的类并进行扩展。
例:OtherClass类,继承自SomeClass
class OtherClass:SomeCLass { ↑ ↑ ... 冒号 基类 }
继承的成员可以被访问,就像它们是派生类自己声明的一样。
例:下面代码声明了类SomeClass和OtherClass
class SomeClass { public string Field1="base class field "; public void Method1(string value) { Console.WriteLine("Base class -- Method1: {0}",value); } } class OtherClass:SomeClass { public string Field2="derived class field"; public void Method2(string value) { Console.WriteLine("Derived class -- Method2: {0}",value); } } class Program { static void Main() { var oc=new OtherClass(); oc.Method1(oc.Field1); //以基类字段为参数的基类方法 oc.Method1(oc.Field2); //以派生字段为参数的基类方法 oc.Method2(oc.Field1); //以基类字段为参数的派生方法 oc.Method2(oc.Field2); //以派生字段为参数的派生方法 } }
没有基类规格说明的类隐式直接派生自类object。
关于类继承的其他重要内容如下
基类和派生类是相对的术语。所有类都是派生类,要么派生自object,要么派生自其他类。
虽然派生类不能删除它继承的任何成员,但可以用与基类同名的成员来屏蔽(mask)基类成员。这是继承的主要功能之一,非常实用。
class SomeClass { public string Field1; ... } class OtherClass:SomeClass { new public string Field1; ... }
例:OtherClass派生自SomeClass,但隐藏了两个继承的成员。
class SomeClass { public string Field1="SomeClass Field1 "; public void Method1(string value) { Console.WriteLine("SomeClass.Method1: {0}",value); } } class OtherClass:SomeClass { new public string Field1="OtherClass Field1";//屏蔽基类成员 new public void Method1(string value)//屏蔽基类成员 { Console.WriteLine("OtherCLass.Method1: {0}",value); } } class Program { static void Main() { var oc=new OtherClass(); oc.Method1(oc.Field1); } }
如果派生类必须完全的访问被隐藏的继承成员,可以使用基类访问(base access)
Console.WriteLie("{0}",base.Field1);
例:派生类OtherClass隐藏了基类的Field1,但可以使用基类访问表达式访问它
class SomeClass { public string Field1="Field1 -- In the base class"; } class OtherClass:SomeClass { new public string Field1="Field1 -- In the derived class"; public void PrintField1() { Console.WriteLine(Field1); Console.WriteLine(base.Field1); } } class Program { static void Main() { var oc=new OtherClass(); oc.PrintField1(); } }
如果你的程序代码经常使用base进行基类访问,你可能需要重新评估类的设计。一般来说能有更优雅的设计,但在没有其他方法的时候也可使用这个特性。
如果有一个派生类对象的引用,就可以获取该对象基类部分的引用。
例:使用基类引用
MyDerivedClass derived=new MyDerivedClass(); MyBaseClass mybc=(MyBaseClass)derived;
例:两个类的声明和使用
class MyBaseClass { public void Print() { Console.WriteLine("This is the base class."); } } class MyDerivedClass:MyBaseClass { new public void Print() { Console.WriteLine("This is the derived class"); } } class Program { static void Main() { var derived=new MyDerivedClass(); var mybc=(MyBaseClass)derived; derived.Print(); mybc.Print(); } }
虚方法可以使基类的引用访问“升至”派生类内。
可以使用基类引用调用派生类的方法,只需满足下面的条件。
例:virtual、override演示
class MyBaseClass { virtual public void Print() ... } class MyDerivedClass:MyBaseCLass { override public void Print() ... }
下图阐明了这组virtual和override方法。注意和上一种情况(用new隐藏基类成员)相比在行为上的区别
下面的代码和上一节相同,但由于使用了virtual和override,产生的结果大不相同。
class MyBaseClass { virtual public void Print() { Console.WriteLine("This is the base class."); } } class MyDerivedClass:MyBaseClass { override public void Print() { Console.WriteLine("This is the derived class"); } } class Program { static void Main() { var derived=new MyDerivedClass(); var mybc=(MyBaseClass)derived; derived.Print(); mybc.Print(); } }
其他关于virtual和override的重要信息
覆写方法可以在继承的任何层次出现。
下面来看看,在MyBaseClass中Print标记为virtual,在MyDerivedClass中Pring标记为override。在SecondDerived中,使用override或new声明Print,两种情况的区别。
class MyBaseClass { virtual public void Print() { Console.WriteLine("This is the base class."); } } class MyDerivedClass:MyBaseClass { override public void Print() { Console.WriteLine("This is the derived class"); } } class SecondDerived:MyDerivedClass { ... }
情况1:使用override声明Print
如果把SecondDerived的Print方法声明为override,那么它会覆写方法的全部两个低派生级别版本。如下图所示,如果一个基类的引用被用于调用Print,它会向上传递通过整个链达到类SecondDerived中的实现。
下面的代码实现了这种情况。注意Main方法最后两行代码。
class SecondDerived:MyDerivedClass { override public void Print() { Console.WriteLine("This is the second derived class"); } } class Program { static void Main() { var derived=new SecondDerived(); mybc=(MyBaseClass)derived; derived.Print(); mybc.Print(); } }
情况2:使用new声明Print
使用new时,当方法通过SecondDerived的引用调用时,结果与情况1相同。但当方法通过MyBaseClass的引用调用时,方法调用只向上传递了一级,在MyDerived那就被执行。
class SecondDerived:MyDerivedClass { new public void Print() { Console.WriteLine("This is the second derived class"); } } class Program { static void Main() { var derived=new SecondDerived(); mybc=(MyBaseClass)derived; derived.Print(); mybc.Print(); } }
前面几节详述了如何在方法上使用virtual/override。其实在属性和索引器上也一样。
例:属性的virtual/override
class MyBaseClass { private int _myInt=5; virtual public int MyProperty { get{return _myInt;} } } class MyDerivedClass:MyBaseClass { private int _myInt=10; override public int MyProperty { get{return _myInt;} } } class Program { static void Main() { var derived=new MyDerivedClass(); var mybc=(MyBaseClass)derived; Console.WriteLine(derived.MyProperty); Console.WriteLine(mybc.MyProperty); } }
创建一个实例过程中的第一件事是初始化对象的所有实例成员。然后调用基类的构造函数,最后执行该类自己的构造函数。
警告 在构造函数中调用虚方法是极不推荐的。在执行基类的构造函数时,基类的虚方法会调用派生类的覆写方法,但这是在执行派生类的构造函数方法体之前。因此,调用会在派生类没有完成初始化之前传递到派生类。
默认情况下,构造对象时,将调用基类的无参数构造函数。但构造函数可以重载,所以基类可能有一个以上的构造函数。如果希望派生类使用一个指定的基类构造函数而不是无参数构造函数,必须在构造函数初始化语句中指定它。
例:构造函数示例
public MyDerivedClass(int x,string s):base(s,x { ... }
当声明一个不带构造函数初始化语句的构造函数时,它实际上是带有base()构造函数初始化语句的简写形式,如下图。
另外一种形式的构造函数初始化语句可以让构造过程(实际上是编译器)使用当前类中其他的构造函数。
例:使用同一个类中具有两个参数的构造函数
public MyClass(int x):this(x,"Using Default String") { ... }
这种语法也常用于另一种情况:一个类有好几个构造函数,并且它们都需要在对象构造开始时执行一些公共的代码。对于这种情况,可以把公共代码提取出来作为一个构造函数,被其他所有的构造函数作为构造函数初始化语句使用,减少代码冗余。
类的可访问性有两个级别:public和internal
下图阐明了internal和public类从程序集外部的可访问性。类MyClass对左边程序集内的类不可见,因为MyClass被标记为internal。然而,类OtherClass对于左边的类可见,因为它是public。
迄今为止,我们一直在同一程序集内声明基类和派生类。但C#也允许从不同程序集定义基类和派生类。
要从不同程序集定义基类、派生类,必须具备以下条件。
例:程序集间继承示例
第一段代码创建了含有MyBaseClass类的程序集,该类有以下特征
//源文件名称为Assembly1.cs using System; namespace BaseClassNS { public class MyBaseClass { public void PrintMe() { Console.WriteLine("I am MyBaseClass"); } } }
第二段代码含有DerivedClass类的声明,该源文件名称为Assembly2.cs
//源文件名称为Assembly2.cs using System; using BaseClassNS; ↑ 包含基类声明的命名空间 namespace UsesBaseClass { class DerivedClass:MyBaseClass {} class Program { static void Main() { var mdc=new DerivedClass(); mdc.PrintMe(); } } }
对类的可访问性,只有两种修饰符:internal、public。本节阐述成员的可访问性。
类的可访问性描述了类的可见性;成员的可访问性描述了类成员的可见性。
在讲解成员访问性的细节前,先阐述一些通用内容.
public class MyClass { public int Member1; private int Member2; protected int Member3; internal int Member4; protected internal int Member5; ... }
另一个类(如类B)能否访问MyClass类中的成员取决于两个特征
上面两个特征划分出4个集合。
这些特征用于定义5种访问级别,下面详细介绍。
public访问级别限制性最少。所有类,包括程序集内部的类和外部的类都可以自由地访问成员。
私有成员访问级别限制最严格
protected访问级别如同private访问级别,除了一点,它允许派生自该类的类访问该成员。(注意,即使程序集外部继承该类的类也能访问该成员)
internal成员对程序集内部的所有类可见,但对程序集外部的类不可见。
protected internal的成员对所有继承该类的类以及所有程序集内部的类可见。
注意,这是protected和internal的并集。
抽象成员指设计为被覆写的函数成员。抽象成员有以下特征
例:抽象方法和抽象属性
abstract public void PrintStuff(string s); abstract public int MyProperty { get; set; }
关于抽象成员的注意事项:
抽象类指设计为被继承的类。抽象类只能被用作其他类的基类。
abstract class AbClass { public void IdentifyBase() { Console.WriteLine("I am AbClass"); } abstract public void IndetifyDerived(); } class DerivedClass:AbClass { override public void IdentifyDerived() { Console.WriteLine("I am DerivedClass"; } } class Program { static void Main() { // AbClass a=new AbClass();//错误,抽象类不能实例化 var b=new DerivedClass(); b.IdentifyBase(); b.IdentifyDerived(); } }
例:包含数据成员和函类型成员的抽象类
abstract class MyBase { public int SideLength=10; const int TriangleSideCount=3; abstract public void PrintStuff(string s); abstract public int MyInt{get;set;} public int PerimeterLength() { return TriangleSideCount*SideLength; } } class MyCLass:MyBase { public override void PrintStuff(string s) { Console.WriteLine(s); } private int _myInt; public override int MyInt { get{return _myINt;} set{_myInt=value;} } } class Program { static void Main() { var mc=new MyClass(); mc.PrintStuff("This is a string."); mc.MyInt=28; Console.WriteLine(mc.MyInt); Console.WriteLine("Perimeter Length:{0}",mc.PerimeterLength()); } }
抽象类必须用作基类,它不能被实例化。
密封类与抽象类相反。
静态类中所有成员都是静态的。静态类用于存放不受实例数据影响的数据和函数。静态类常见用途就是创建一个包含一组数学方法和值的数学库。
可以使用类名和成员名,像访问其他静态成员那样访问它的成员。
例:静态类示例
static public class MyMath { public static float PI=3.14f; public static bool IsOdd(intx) { return x%2==1; } public static int Times2(int x) { return 2*x; } } class Program { static void Main() { int val=3; Console.WriteLine("{0} is odd is {1}",val,MyMath.IsOdd(val)); Console.WriteLine("{0} * 2 = {1}",val,MyMath.Time2(val)); } }
扩展方法允许编写的方法和声明它的类之外的类关联。
扩展方法的重要要求如下:
例:扩展方法示例
namespace ExtensionMethods { sealed class MyData { private double D1,D2,D3; public MyData(double d1,double d2,double d3) { D1=d1;D2=d2;D3=d3; } public double Sum() { return D1+D2+D3; } } static class ExtendMyData { public static double Average(this MyData md) { return md.Sum()/3; } } class Program { static void Main() { var md=new MyData(3,4,5); Console.WriteLine("Sum: {0}",md.Sum()); Console.WriteLine("Average: {0}",md.Average()); } } }
from: http://www.cnblogs.com/moonache/p/6120697.html
标签:冗余 abc 签名 程序代码 赋值 dde 成员 关联 strong
原文地址:https://www.cnblogs.com/GarfieldEr007/p/10126557.html