C# 之 4个访问修饰符和8个声明修饰符详解
一、4个访问修饰符(是添加到类、结构或成员声明的关键字)
[1] Public:公有的,是类型和类型成员的访问修饰符。对其访问没有限制。
[2] Internal:内部的,是类型和类型成员的访问修饰符。同一个程序集中的所有类都可以访问
[3] Private:私有的,是一个成员访问修饰符。只有在声明它们的类和结构中才可以访问。
[4] Protected:受保护的,是一个成员访问修饰符。只能在它的类和它的派生类中访问。
[5] protected internal:访问级别为 internal 或 protected。即,“同一个程序集中的所有类,以及所有程序集中的子类都可以访问。
注意点:
一个成员或类型只能有一个访问修饰符,使用 protected internal组合时除外。
如果在成员声明中未指定访问修饰符,则使用默认的可访问性
类型成员默认的可访问性
|
属于 |
默认的成员可访问性 |
该成员允许的声明的可访问性 |
|
enum |
public |
无 |
|
class |
private |
public protected internal private protected internal |
|
interface |
public |
无 |
|
struct |
private |
public internal private |
Internal 和 protected internal 详解(即什么是同一个程序集)
示例1:(这里同一个程序集指同一个命名空间)
using System;
using System.Collections.Generic;
using System.Text;
namespace Example05Lib
{
public class Class1
{
internal String strInternal = null;
public String strPublic;
internal protected String strInternalProtected = null;
}
} using System;
using System.Collections.Generic;
using System.text;
namespace Example05Lib
{
class Class2
{
private String tmpStr=new Class1().strInternal;
private String tmpStr=new Class1().strInternalProtected;
private String tmpStr=new Class1().strPublic;
}
}
1.1结果: Class2 类可以访问到 Class1 的 strInternal 成员,当然也可以访问到 strInternalProtected 成员,因为他们在同一个程序集里
using System;
using System.Collections.Generic;
using System.text
using Example05Lib
namespace Example05
{
class Program
{
class Class3:Class1
{
public Class3()
{
base.StrInternalProtected;
base.strPublic;
}
}
}
}
1.2结果:Class3 类无法访问到 Class1 的 strInternal 成员,因为它们不在同一个程序集里。但却可以访问到 strInternalProtected 成员,因为 Class3 是 Class1 的继承类。
using System;
using System.Collections.Generic;
using System.text
using Example05Lib
namespace Example05
{
class Program
{
static void Main(string[] args)
{
String tmpStr=new Class1().strPublic;
}
}
}
1.3结果:无法访问到 strInternalProtected 与strInternal 成员,因为它们既不在同一个程序集里也不存在继承关系
示例2(在这里同一个程序集是指同一个.cs文件,不同的.cs文件的命名空间省略)
2.1该示例包含两个文件:Assembly1.cs 和 Assembly2.cs。第一个文件包含内部基类 BaseClass。在第二个文件中,实例化 BaseClass 的尝试将产生错误。
internal class BaseClass
{
public static int intM = 0;
}
class TestAccess
{
static void Main()
{
BaseClass myBase = new BaseClass(); // CS0122
}
}
2.2 使用与示例 1 中所用的文件相同的文件,并将 BaseClass 的可访问性级别更改为 public。还将成员 IntM 的可访问性级别更改为 internal。在此例中,您可以实例化类,但不能访问内部成员。
public class BaseClass
{
internal static int intM = 0;
}
public class TestAccess
{
static void Main()
{
BaseClass myBase = new BaseClass(); // Ok.
BaseClass.intM = 444; // CS0117
}
}
示例3
对于一些大型的项目,通常由很多个DLL文件组成,引用了这些DLL,就能访问DLL里面的类和类里面的方法。比如,你写了一个记录日志的DLL,任何项目只要引用此DLL就能实现记录日志的功能,这个DLL文件的程序就是一个程序集。
如果你记录日志的程序集是这么定义的
namespace LogerHelper
{
internal class aa
{
public void bb()
{
return "";
}
}
public class Write
{
public void WriteIn(string content)
{
class x = new aa();
x.bb();
}
}
}
当另一个项目引用了此DLL
它可以这么访问
LogerHelper.Write x = new LogerHelper.Write();
x.WriteIn("");
但不可以这么访问
LogerHelper.aa x = new LogerHelper.aa();
x.bb();
这就叫,只能在程序集中访问
二、8个声明修饰符
[1] Partial:在整个同一程序集中定义分部类和结构。
[2] Static: 声明属于类型本身而不是属于特定对象的成员。
[3] Abstract:抽象类,只能是其他类的基类。类中的方法只声明不实现,方法的实现在他的派生类中完成。
[4] Sealed:指定类不能被继承。
[5] Virtual:用于修饰方法、属性、索引器或事件声明,并且允许在派生类中重写这些对象
[6] Override:提供从基类继承的成员的新实现
[7] New:作修饰符,隐藏从基类成员继承的成员,在不使用 new 修饰符的情况下隐藏成员是允许的,但会生成警告。作运算符,用于创建对象和调用构造函数。
[8] Extern:用于声明在外部实现的方法。 extern 修饰符的常见用法是在使用 Interop 服务调入非托管代码时与 DllImport 特性一起使用。 在这种情况下,还必须将方法声明为 static
Virtual,override和new 的区别
[1] virtual和override配套使用。在基类base中声明了虚方法method()并用virtual修饰,在子类derived中重写方法method()并用override修饰。那么当将子类的实例赋予基类的对象(不需要强制转换)时即Base Bclass= new Derived();Bclass.Method()是调用了子类的method()方法,而不是基类的。
[2] new不需要和virtual配套使用。在基类base中声明了方法method(),在子类derived中声明了同名的方法method()并用new修饰。那么当将子类的实例赋予基类的对象时即Base Bclass= new Derived();Bclass.Method()是调用了基类类的method()方法,而不是子类的。
[3] 这说明,override可以覆盖基类的方法,让基类的方法以子类的内容实现,而new不用来覆盖基类的方法,而是全新定义一个子类的方法,这个方法只属于子类,与基类的方法无关,只是名字上相同而已。
下面,我以例子来说明他们之间的微妙区别:
public class GrandClass//基类
{
public GrandClass()
{
Console.WriteLine("In GrandClass.Constructor");
}
public virtual void Method()//用virtual才可以在子类中用override,而new不需要这样
{
Console.WriteLine("In GrandClass.Method()");
}
}
public class ParentClass:GrandClass//继承基类,看看override状态
{
public ParentClass()
{
Console.WriteLine("In ParentClass.Constructor");
}
public override void Method()//使用override,是说把基类的方法重新定义
{
Console.WriteLine("In ParentClass.Method() use override");
}
}
public class NewParentClass:GrandClass//继承基类,看看new状态
{
public NewParentClass()
{
Console.WriteLine("In NewParentClass.Constructor");
}
new public void Method()//使用new,不是说用到基类的方法,而是重新定义一个子类方法,只不过,方法名称与基类相同
{
Console.WriteLine("In NewParentClass.Method()");
}
}
下面的调用代码:
static void Main()
{
GrandClass Parent=(GrandClass)new ParentClass();//用override子类加框一个基类对象句柄
Parent.Method();
GrandClass NewParent=(GrandClass)new NewParentClass();//用new子类加框一个基类对象句柄
NewParent.Method();
NewParentClass NewParent1=new NewParentClass();//一个子类句柄
NewParent1.Method();
}
结果是这样的:
[1]In GrandClass.Constructor
[2]In ParentClass.Constructor
[3]In ParentClass.Method() use override
[4]In GrandClass.Constructor
[5]In NewParentClass.Constructor
[6]In GrandClass.Method()
[7]In GrandClass.Constructor
[8]In NewParentClass.Constructor
[9]In NewParentClass.Method()
结果前的序号是我自己加的.为了以下的分析:
[1],[2]两句是GrandClass Parent=(GrandClass)new ParentClass();的结果.(注意一下子类构建器与基类构建器的初始化顺序)
[3]是Parent.Method();结果.
[4],[5]两句是GrandClass NewParent=(GrandClass)new NewParentClass();的结果.
[6]是NewParent.Method();的结果.
[7],[8]两句是GrandClass NewParent1=(GrandClass)new NewParentClass();的结果.
[9]是NewParent1.Method();的结果.
这里我们可以看到,同样是用子类的对象构造一个基类句柄.结果却很明显,可以看到[3]和[6]的区别.[3]调用了子类的Method(),而[6]调用了基类的Method().
这说明,override可以覆盖基类的方法,让基类的方法以子类的内容实现,而new不用来覆盖基类的方法,而是全新定义一个子类的方法,这个方法只属于子类,与基类的方法无关,只是名字上相同而已.
而这一例子的基础是建立在用子类对象加框成基类对象的,目的是实现用基类句柄调用子类方法,以实现重载的多态性.
如果想调用子类的new方法,用子类的句柄(绝对不能用基类句柄)来调用.结果[9]可以看出来.
用new是在为子类定义方法名时,实在没有办法定义方法名的情况才与基类的方法相同,但这个方法只在子类中起到作用,而不影响基类的方法.也就是说,new方法就是子类新定义的方法.用override是直正意义上的重载.
C# 之 4个访问修饰符和8个声明修饰符详解的更多相关文章
- 27.28. VUE学习之--事件修饰符之stop&capture&self&once实例详解
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- linux下创建用户组与用户 只能访问指定目录的方法 以及FTP用户配置详解
VSFTPD 安装: -- 查看是否已经安装 VSftpd: rpm -qa | grep vsftp yum install -y vsftpd groupadd ftpuser #创建ftpuse ...
- Java 访问修饰符详解
访问修饰符定义了类.属性和方法的访问权限,Java 中包含四种,访问权限从小到大为 private.default.protected 和 public. public,公共修饰符,被其修饰的类.属性 ...
- java中四种访问修饰符区别及详解全过程
客户端程序员:即在其应用中使用数据类型的类消费者,他的目标是收集各种用来实现快速应用开发的类. 类创建者:即创建新数据类型的程序员,目标是构建类. 访问控制存在的原因:a.让客户端程序员无法触及他们不 ...
- C# 中4个访问符和8个修饰符详解
4个访问修饰符(是添加到类.结构或成员声明的关键字) Public:公有的,是类型和类型成员的访问修饰符.对其访问没有限制. Internal:内部的,是类型和类型成员的访问修饰符.同一个程序集中的所 ...
- java中4种修饰符访问权限的区别及详解全过程
java中4种修饰符访问权限的区别及详解全过程 http://jingyan.baidu.com/article/fedf0737700b3335ac8977ca.html java中4中修饰符分别为 ...
- abstract关键字、final关键字、static关键字、访问修饰符详解
abstract关键字.final关键字.static关键字.访问修饰符详解 abstract关键字: final关键字: static关键字: 访问修饰符:
- 详解java访问修饰符
详解java访问修饰符 为了防止初学者看到因为专业的术语而感觉晦涩难懂,我接下来尽量用生动比喻的说法来解释!首先第一点,我们来讲讲什么叫修饰符!看看这个名称,想想他的意思.修饰符!修饰符!,就是用来修 ...
- C#.net 中 修饰符 详解 (来自MSDN)
自己理解的不够深刻,无奈基础较差!记上一笔,记忆深刻些,哈哈…… 1. 访问修饰符 public 同一程序集中的任何其他代码或引用该程序集的其他程序集都可以访问该类型或成员. private 只有同一 ...
随机推荐
- python操作Excel的库openpyxl
http://openpyxl.readthedocs.io/en/default/tutorial.html 这里先上该库的文档镇文. 1,遇到合并后的单元格信息读取的问题,通过使用cell中off ...
- cryptsetup文件系统加密
今天做了SYC攻防题的文件系统挂载部分,在找到挂载最内层的final文件时发现mount无法识别,这也许就是一个加密的文件系统吧,还好-在龟速的 网络环境下查阅到了losetup循环挂载系统命令,但是 ...
- InnoDB 与 MYISAM的区别和联系
1.存储引擎是什么? MySQL中的数据用各种不同的技术存储在文件(或者内存)中.这些技术中的每一种技术都使用不同的存储机制.索引技巧.锁定水平并且最终提供广泛的不同的功能和能力.通过选择不同的技术, ...
- 是armhf,还是armel?
本文译至:https://blogs.oracle.com/jtc/entry/is_it_armhf_or_armel ARM处理器有各种品牌和规格,其中一部分的原因涉及到市场问题,成本,大小和功耗 ...
- 【原创】大数据基础之Marathon(2)marathon-lb
marathon-lb 官方:https://github.com/mesosphere/marathon-lb 一 简介 Marathon load balancer (Marathon-LB) i ...
- MYSQL修改字段
当字段为空则插入0,不为空则原来的值 UPDATE t_pm_scheduleSET lesson_room_id1 = IFNULL(lesson_room_id1, 0), lesson_roo ...
- MySQL笔记二
Ø function 函数 函数的作用比较大,一般多用在select查询语句和where条件语句之后.按照函数返回的结果, 可以分为:多行函数和单行函数:所谓的单行函数就是将每条数据进行独立的计算,然 ...
- easyui生成合并行,合计计算价格
easyui生成合并行,合计计算价格 注:本文来源: 原创 一:图样你效果图 二:代码实现 1:datagrid 列展示: window.dataGrid = $("#dataGrid&qu ...
- Confluence 6 配置快速导航
当在 Confluence 中的快速导航进行查找的时候(请查看 Searching Confluence)能够帮助你显示页面下拉列表和其他的项目,这个是通过查找页面标题进行比对的.在默认情况下,这个功 ...
- OC对象本质
@interface person:NSObject{ @public int _age; } @end @implementation person @end @interface student: ...