定义类、System.Object对象、构造函数与析构函数、抽象类与静态类

时间:2022-09-01 14:01:38

一、类定义

class MyClass
{
//类成员
}

1、访问级别

默认访问级别为internal(内部类),也可以是public(公共类)

  • internal(内部类):当前项目中的代码才能访问
  • public(公共类):任何地方都能访问
public class MyClass
{
//类成员
}

2、继承修饰符

  • abstract(抽象类):不能实例化,只能继承。
  • seald(密封类):不能被继承,无派生类。
  • static(静态类):只包含静态成员的类。
public sealed class MyClass
{
//类成员
}

二、类继承

c#中,一个类只能有一个基类,类默认继承自System.Object类。

public class MyBase
{
//基类
}
public class MyDerivedClass : MyBase
{
//派生类
}

一个类可以实现多个接口。当一个类既继承自一个基类,又实现接口时,基类必须紧跟在冒号的后面,之后才是接口。

public class MyDerivedClass : MyBase, IMyInterface
{
//派生类
}

三、System.Object的成员

  • Object():构造函数,初始化 Object 类的新实例。
  • ~Object():析构函数,引用 Finalize()函数,在垃圾回收将某一对象回收前允许该对象尝试释放资源并执行其他清理操作。Finalize()可重写。
  • Equals(Object):静态方法。确定指定的对象是否等于当前对象。可重写。
  • Equals(Object, Object):静态方法。确定指定的对象实例是否被视为相等。
  • GetHashCode():作为默认哈希函数。可重写。
  • GetType():获取当前实例的类型。虚方法,用于在运行时通过查询对象元数据来获取对象的运行时类型。子类无法通过覆写GetType()而篡改类型信息,从而保证了类型安全。
void Main()
{
MyBaseClass myBase = new MyBaseClass();
MyDerivedClass myDerived = new MyDerivedClass();
object o = myDerived;
MyBaseClass b = myDerived;
Console.WriteLine(myBase.GetType());//UserQuery+MyBaseClass
Console.WriteLine(myDerived.GetType());//MyDerivedClass
Console.WriteLine(o.GetType());//MyDerivedClass
Console.WriteLine(b.GetType());//MyDerivedClass
} class MyBaseClass
{ } class MyDerivedClass : MyBaseClass
{
}

    在.Net中,下面的方法能够实现与System.Object的GetType()方法相同的效果:

  1. Type.GetType()静态方法

  2. typeof运算符
Type t = Type.GetType("ConsoleApplication.Person");
Type t = typeof(ConsoleApplication.Person);
  • MemberwiseClone():创建当前 Object 的浅表副本。

对类里的引用对象只克隆地址,其实还是指向同一个对象。所以仅仅能在类或派生的类中使用。

void Main()
{
A a = new A();
A b = a;
b.M = "b";
Console.Write(a.M);//b
Console.Write(b.M);//b
} class A : System.ICloneable
{
public string M = "a";
public object Clone()
{
return (object)this.MemberwiseClone(); ;
}
}
  • ReferenceEquals(Object, Object):确定指定的 Object 实例是否是相同的实例。
  • ToString():返回表示当前对象的字符串。默认返回对象带命名空间的全名。可重写。

假设继承类须要在处理字符串格式化、语言文化方面控制很多其它格式化输出,则须要实现IFormattable接口。
大部分.Net基本类型都实现了IFormattable接口,用于实现更灵活的字符串信息输出。IFormattable接口的定义如下:

public interface IFormattable
{
string ToString(string format, System.IFormatProvider formatProvider);
}

四、构造函数(Construction)与析构函数(Destruction)

c#中,通常不需要定义类的构造函数和析构函数,因为基类System.Object已提供了默认的实现方式。(自动生成一个不带参数的构造函数,为字段初始化为默认值。)

也可以提供自己的构造函数和析构函数,用于初始化对象和清理对象。

class MyClass
{
public MyClass()//默认构造函数。显式定义了默认构造函数,就不会自动生成一个不带参数的构造函数了。
{
}
public MyClass(int a)//带参数的构造函数
{
}
}

1、私有构造函数:

保证类不能实例化。

public sealed class Singleton
{
private static readonly Singleton instance = new Singleton();
private Singleton()
{
}
public static Singleton Instance
{
get { return instance; }
}
}

2、静态构造函数:

对类(而不是对实例)进行一些初始化,在创建类第一个实例或引用任何静态成员之前,将自动调用静态构造函数,并且只执行一次。此函数不可继承。

作用:用于初始化一些静态数据,或用于执行仅需执行一次的特殊操作。

class MyClass
{
static readonly long baseline; static MyClass()//无访问修饰符,无参数,只有一个static标记。
{
baseline=DateTime.Now.Ticks;
}
}

1、无参数构造函数也可与静态函数共存,尽快参数列相同,但一个属于类,一个属于实例,不会冲突。

2、若未写静态构造函数,而类中包含有初始值设定的静态成员,将会自动使用默认的静态构造函数。

3、继承中构造函数的执行序列:

构造函数不继承基类的构造函数,自动调用基类默认构造函数。

1、默认执行序列,默认为base(),即先执行基类的默认构造函数,再执行派生类的构造函数,基类的默认构造函数此时需要显示创建。

void Main()
{ B objB1=new B();//1-4
B objB2=new B("a");//1-5
B objB3=new B("a","b");//1-6
} class A
{
public A()
{
Console.WriteLine("1");
}
public A(string a)
{
Console.WriteLine("2");
} public A(string a, string b)
{
Console.WriteLine("3");
}
} class B : A
{
public B()
{
Console.WriteLine("4");
}
public B(string a)
{
Console.WriteLine("5");
} public B(string a, string b)
{
Console.WriteLine("6");
}
}

2、基类中带参数的构造函数,派生类必须显示调用。

void Main()
{
B objB1 = new B();//2-6-4
//显式使用base调用基类的特定构造函数,则不执行基类的默认构造函数。
} class A
{
public A()
{
Console.WriteLine("1");
}
public A(string a)
{
Console.WriteLine("2");
} public A(string a, string b)
{
Console.WriteLine("3");
}
} class B : A
{
public B() : this("a", "a")
{
Console.WriteLine("4");
}
public B(string a)
{
Console.WriteLine("5");
} public B(string a, string b) : base(a)
{
Console.WriteLine("6");
}
}

4、析构函数

当进行垃圾回收时,就会执行析构函数,以释放资源。在调用这个析构函数后,还将隐式的调用基类的析构函数,包括System.Object中Finalize()函数。

class MyClass
{
~MyClass()
{ }
}

注意:我们不能依赖析构函数释放资源,因为在进行垃圾回收前,资源可能长时间占用,使用using关键字,可再代码尾自动调用对象的Dispose()方法。

void Main()
{
using (MyClass A = new MyClass())
{
//---
}
} class MyClass : IDisposable
{
public void Dispose()
{
//----
}
}

五、接口的定义

interface IMyInterface //接口默认访问级别为internal,也可以是public
{
//接口成员
}

六、抽象类

使用方法

  • 抽象类关键字可用于类、方法、属性、索引器及事件。
  • 抽象类不能实例化。
  • 派生的子类必须包括父类所有抽象成员的实现。
  • 抽象方法和抽象属性只允许在抽象类中。
  • 抽象成员不提供实现。
void Main()
{
A b = new B();
b.X = 10;
b.F();//BF
b.M();//BM //如果B不重写M方法,则b.M()返回AM
B.N();//static
A.N();//static
} abstract class A
{
protected int _x;
public abstract int X//抽象属性
{
get; set;
}
public abstract void F();//抽象方法
public virtual void M()//虚拟方法,可继承
{
Console.Write("AM");
}
public static void N()//静态方法,可继承
{
Console.Write("static");
}
} class B : A
{ public override int X//必须重写属性X
{
get { return _x; }
set { _x = value; }
}
public override void F()//必须重写方法F
{
Console.Write("BF");
}
public override void M()//可以重写方法M
{
Console.Write("BM");
}
}

抽象类和接口的区别

相同点:都包含可以由派生类继承的成员,都不能直接实例化,但都可以声明他们类型的变量。

不同点:

1、接口所有成员都没有代码体,抽象类可以有抽象成员和非抽象成员(可以是虚拟的,以便重写)。

2、接口成员默认是公共的,抽象成员可以是private,protected,internal等。

3、接口只有成员、方法、属性和事件,抽象类还可以有字段、构造函数、析构函数、静态成员或常量。

4、接口用作完成某些相同的任务,抽象类主要用作共享某些主要特性。

七、静态类

例如System.Math类,静态类的所有成员都是静态,默认继承自System.Object,不能从其他类派生,也不能实现接口。

  • 1、静态类可以有静态构造函数。
  • 2、静态类是密封的,不可被继承。
  • 3、静态类最大的特点就是共享。
static class MyClass
{
public static MyClass()
{
//--
}
}