今天跟大家分享一下关于访问限定和数据成员的知识。主要包括以下两点:
类和方法有一些访问限定符,如private,public等。除此之外,还包含一些预定义特性。下面几个你都知道吗?
要想既不能实例化又不能被继承? 需要两个步骤:
sealed class Demo
{
private Demo() { }
...
}
public abstract class Animal
{
public abstract void Shout();
}
实例:
public class Animal //基类
{public virtual void Shout() //定义虚方法
{Console.WriteLine("逼我发威啊!"); //虚方法实现
}
}
public class Dog : Animal
{public override void Shout() //override重写基类方法
{Console.WriteLine("汪汪!");
}
}
public class Cat : Animal
{public new void Shout() //new隐藏基类方法
{Console.WriteLine("喵喵~~");
}
}
class Program
{static void Main(string[] args)
{new Animal().Shout(); //“逼我发威啊!”
new Dog().Shout(); //“汪汪!”
new Cat().Shout(); //”喵喵~~”
Console.WriteLine("**************************");
Animal a1 = new Dog();
a1.Shout(); //重写了基类的方法 “汪汪!”
Animal a2 = new Cat();
((Cat)a2).Shout(); //派生类中的方法隐藏了基类的方法 ”喵喵~~”
a2.Shout(); //基类的方法没有被修改,只是被隐藏 “逼我发威啊!”
Console.Read();
}
}
常量是恒定不变的,在编译时就确定了它的值,编译后直接将值存到元数据中。变量类型只能是编译器能直接识别的基元类型,不能是引用类型,因为引用类型需要在运行时调用构造函数进行初始化。
我们给段代码实际看一下:
class TestConst
{
public const int Number = 100; //声明常量并赋值
public string GetName()
{
const string name = "XiaoJing"; //常量用作局部变量
return name;
}
}class Program
{static void Main(string[] args)
{
Console.WriteLine("const:The total number is " + TestConst.Number);
Console.Read();
}
}
通过ILDasm工具查看一下,const变量编译后为static literal类型,所以不难理解,常量是针对类的一部分,而不是实例的一部分。这样它才能保证是恒定不变的。
在使用常量时,编译器从常量模块的元数据中直接取出常量的值,嵌入到IL代码中。所以在声明常量的时候就要为它初始化值。例如上面的例子,Number直接替换为值100。
Main函数的IL代码如下:
还有一点,const常量也可以用于局部变量,例如上面的GetName()方法。
类的数据成员通常用来保存一个值类型的实例或者指向引用类型的引用,CLR支持读写和只读两种数据成员,其中只读数据成员使用readonly修饰的。看个实际例子:
class TestReadonly
{
public readonly int Number = 100; //只读实例成员
public TestReadonly()
{
Number = 200; //构造器中重新赋值
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("readonly:The total number is " + new TestReadonly().Number);
Console.Read();
}
}
通过ILDasm.exe工具查看, Readonly实例成员编译后为 initonly修饰。这个例子是只读实例成员,readonly也可以修饰静态只读成员,需要在类静态构造器中初始化,这里就不赘述了。
数据成员是在类的实例构造过程中分配内存的,因此能在运行时刻获取它的值。因此只读成员类型没有限制,可以是基元类型,也可以是引用类型。而且可以在构造器中赋值,声明时赋值与否都可以。
我们查看main函数的IL代码:可以看出首先对TestReadonly类进行实例化,然后读取实例的Number成员的值,是在运行过程中获取值的。
还有要注意的一点,readonly不能用作局部变量,否则编译时就会报错。
最后我们要说明的是,readonly字段不能改变的是引用,而不是字段引用的对象。例如
运行结果是
a
X