一、修饰符
访问修饰符:
修饰符 | 应用范围 | 可访问范围 |
public | 类、方法、属性、变量 | 任何地方均可以访问。 |
protected | 类、方法、属性、变量 | 只能在派生类中访问。 |
internal | 类、方法、属性、变量 | 在包含它的应用程序中可访问。 |
private | 类、方法、属性、变量 | 只有在类自身中访问。 |
protected internal | 类、方法、属性、变量 | 在包含它的应用程序和派生类型中访问。 |
其他修饰符:
修饰符 | 应用范围 | 说明 |
new | 方法、属性 | 任何地方均可以访问。 |
static | 类、方法、属性、变量 | 可以不在类的实例化对象上执行。 |
virtual | 方法、属性 | 方法可以由派生类重写。 |
abstract | 类、方法、属性 | 抽象类不能实例化。 |
override | 方法、属性 | 重写继承的方法。 |
sealed | 类、方法、属性 | 密封类不能继承。 |
访问修饰符可以和除static某些情况以外的其他修饰符一起使用。
二、说明
new:用于派生类的方法,其方法可以是非虚拟方法(virtual Method)。
在用作修饰符时,new 关键字可以显式隐藏从基类继承的成员。隐藏继承的成员意味着该成员的派生版本将替换基类版本。在不使用 new 修饰符的情况下隐藏成员是允许的,但会生成警告。使用 new 显式隐藏成员会取消此警告,并记录代之以派生版本这一事实。
例:
public class BaseC
{
public int x;
public void Invoke() {}
}
public class DerivedC : BaseC
{
new public void Invoke() {}
}
static:
使用static修饰符声明属于类型本身而不是属于特定对象的静态成员。static 修饰符可用于类、字段、方法、属性、运算符、事件和构造函数,但不能用于索引器、析构函数或类以外的类型。
1、 如果对类应用 static 关键字,则该类的所有成员都必须是静态的。
2、 尽管类的实例包含该类所有实例字段的单独副本,但每个静态字段只有一个副本。
3、 类(包括静态类)可以有静态构造函数。可以再定义普通的无参数构造函数或使用编译器提供的默认构造函数。static构造函数必须是无参数的,且不能与访问修饰符一起来修饰构造函数。
4、 第一次调用类的static属性或方法时,如果有static构造函数会先执行static构造函数,且只执行这一次。
5、 static构造函数初始化的类属性必须是static属性,即不能初始化和使用类的非static属性和非static方法。static属性可以用static构造函数来初始化或static方法调用,也可以不用。但不可以使用 this 来引用静态方法或属性访问器。
例:
public class A
{
static A()
{
Str = "sdf";
}
public A()
{
Str = "12345";
}
public static string Str;
}
MessageBox.Show(A.Str);
此时,A.Str="sdf"。如果在MessageBox.Show(A.Str)前增加一句:A A1 = new A();,则A.Str="12345"。
virtual:用于修饰方法、属性、索引器或事件声明,并且允许在派生类中重写这些对象。
1、 默认情况下,方法是非虚拟的。不能重写非虚方法。
2、 virtual 修饰符不能与 static、abstract 和 override 修饰符一起使用。
3、 通过包括使用 override 修饰符的属性声明,可在派生类中重写虚拟继承属性。
abstract:用于修饰类、方法、属性、索引器及事件。在类声明中使用 abstract 修饰符以指示某个类只能是其他类的基类。标记为抽象或包含在抽象类中的成员必须通过从抽象类派生的类来实现。
1、 抽象类不能实例化,只能被继承。所以不能用 sealed修饰符修改抽象类,因为这意味着抽象类不能被继承。
2、 抽象类可以包含抽象方法、抽象属性和抽象访问器。
3、 包含抽象构造函数或抽象方法的类必须是抽象类。但抽象类可以不声明构造函数,也可以声明普通的构造函数。如果没有构造函数,编译器将提供默认的普通无参数构造函数。
4、 从抽象类派生的非抽象类必须包括继承的所有抽象方法和抽象访问器的实实现,即抽象方法是隐式的虚方法,但不允许显式的使用virtual。在派生类中需要用override重写。
5、 因为抽象方法声明不提供实际的实现,所以没有方法体;方法声明只是以一个分号结束,并且在签名后没有大括号 ({ })。
override:
C# 允许派生类包含与基类方法名称相同的方法。
1、 基类方法必须定义为 virtual。
2、 如果派生类中的方法前面没有 new 或 override 关键字,则编译器将发出警告,该方法将有如存在 new 关键字一样执行操作。
3、 如果派生类中的方法前面带有 new 关键字,则该方法被定义为独立于基类中的方法。
4、 如果派生类中的方法前面带有 override 关键字,则派生类的对象将调用该方法,而不调用基类方法。
5、 可以从派生类中使用 base 关键字调用基类方法。
6、 override、virtual 和 new 关键字还可以用于属性、索引器和事件中。
例:
public class A
{
public virtual string GetStr(string S1)
{
return S1 + " 这是A的。";
}
public string GetStr1(string S1)
{
return S1 + " 这是AA的。";
}
}
public class B : A
{
public override string GetStr(string S1)
{
S1 += " 这是B的。";
return base.GetStr(S1);
}
public new string GetStr1(string S1)
{
S1 += " 这是BB的。";
return base.GetStr1(S1);
}
}
Virtual--override和new两种方式,都有达到了虚拟继承的目地。
sealed:用于类、实例方法和属性。密封类不能被继承。密封方法会重写基类中的方法,但其本身不能在任何派生类中进一步重写。当应用于方法或属性时,sealed 修饰符必须始终与 override一起使用。
1、 密封类不能被继承。密封成员不能被派生类重写。
2、 结构是隐式密封的;因此它们不能被继承。
除非有充分的理由,否则不要密封类。
不要因为预见不到需要扩展某个类的情形,就认为将其密封起来是合适的。如果类满足如下条件,则应将其密封:
· 类是静态类。
· 类包含带有安全敏感信息的继承的受保护成员。
· 类继承多个虚成员,并且密封每个成员的开发和测试开销明显大于密封整个类。
· 类是一个要求使用反射进行快速搜索的属性。密封属性可提高反射在检索属性时的性能。
不要在密封类型中声明受保护成员或虚成员。
如果类型是密封的,则它不能有派生类。受保护成员只能从派生类进行访问,虚成员也只能在派生类中重写。
考虑密封重写的成员。
可以使用这种方式来确保派生类不会修改或跳过当前类和所有派生类所需的行为。参考资料:
MSDN
C#高级编程