在 C# 中,public、private、protected 和没有访问修饰符有啥区别?
Posted
技术标签:
【中文标题】在 C# 中,public、private、protected 和没有访问修饰符有啥区别?【英文标题】:In C#, what is the difference between public, private, protected, and having no access modifier?在 C# 中,public、private、protected 和没有访问修饰符有什么区别? 【发布时间】:2010-10-11 12:26:20 【问题描述】:我在大学期间一直在使用public
,想知道public
、private
和protected
之间的区别?
除了一无所有,static
还能做什么?
【问题讨论】:
【参考方案1】:访问修饰符
来自docs.microsoft.com:
public
同一程序集或引用它的其他程序集中的任何其他代码都可以访问该类型或成员。
private
类型或成员只能被同一类或结构中的代码访问。
protected
类型或成员只能由同一类或结构中的代码或派生类中的代码访问。
private protected
(在 C# 7.2 中添加)类型或成员只能由同一类或结构中的代码访问,或者同一程序集的派生类中的代码访问,但不能从另一个程序集访问。
internal
同一程序集中的任何代码都可以访问类型或成员,但不能从另一个程序集中访问。
protected internal
同一程序集中的任何代码或另一个程序集中的任何派生类都可以访问该类型或成员。
当没有设置访问修饰符时,使用默认的访问修饰符。所以总会有某种形式的访问修饰符,即使它没有设置。
static
modifier
类上的 static 修饰符意味着该类不能被实例化,并且它的所有成员都是静态的。静态成员有一个版本,无论创建了多少其封闭类型的实例。
静态类与非静态类基本相同,但有一个区别:静态类不能被外部实例化。换句话说,您不能使用 new 关键字来创建类类型的变量。因为没有实例变量,所以您可以使用类名本身来访问静态类的成员。
但是,有一个 static constructor 这样的东西。任何类都可以有其中之一,包括静态类。它们不能直接调用并且不能有参数(除了类本身的任何类型参数)。在创建第一个实例或引用任何静态成员之前,会自动调用静态构造函数来初始化类。看起来像这样:
static class Foo()
static Foo()
Bar = "fubar";
public static string Bar get; set;
静态类通常用作服务,您可以这样使用它们:
MyStaticClass.ServiceMethod(...);
【讨论】:
你可以在非静态类中拥有静态方法,对吧? 是的,它们的行为方式与我的示例相同。 在这种情况下“装配”一词是什么意思? 静态 - 另外,将其视为全局变量。示例: Console.WriteLine() ... Console 和它的所有方法一样是一个静态类。因此,它们可以通过使用这种形式轻松地在代码中的任何地方使用 - [静态类].[静态方法]() 就像在 Console.WriteLine() 中一样。 Protected 和 Private Protected 有什么区别?对我来说,听起来两者都是一样的..【参考方案2】:图形概述(简而言之)
由于static classes 是密封的,它们不能被继承(从Object 除外),因此关键字protected 在静态类上无效。
如果您没有在前面放置访问修饰符,则默认设置请参见此处:Default visibility for C# classes and members (fields, methods, etc.)?
非嵌套
enum public
non-nested classes / structs internal
interfaces internal
delegates in namespace internal
class/struct member(s) private
delegates nested in class/struct private
嵌套:
nested enum public
nested interface public
nested class private
nested struct private
此外,还有 seal-keyword,它使类不可继承。 另外,在 VB.NET 中,关键字有时是不同的,所以这里有一个备忘单:
【讨论】:
@ᴀʀᴜn BᴇrtiL:你确定吗?不同程序集中的派生类? 我们可以在同一个程序集中派生类,不同的我们不能。我以为你的意思是在同一个程序集中...... @ᴀʀᴜn BᴇrtiL:嗯,对,这实际上应该是孵化的。 我认为图中有错误。如果 internal 用于类,则该类可以由同一程序集中的另一个类派生。此外,如果在属性上使用 internal 修饰符,则也可以在同一程序集中的派生类中访问此属性。也许该图是正确的,因为“包含程序集”下有一个“是”,但它可能会被误解,因为“派生类”下有一个“否”。【参考方案3】:Public - 如果你能看到类,那么你就能看到方法
Private - 如果您是该类的一部分,那么您可以看到该方法,否则不能。
Protected - 与 Private 相同,加上所有 后代 也可以看到该方法。
静态(类) - 还记得“类”和“对象”之间的区别吗?忘记这一切。它们与“静态”相同......该类是其自身的唯一实例。
静态(方法) - 每当您使用此方法时,它都会有一个独立于它所属的类的实际实例的参考框架。
【讨论】:
你不能在非静态类中有静态方法吗? 是的,但我说的是静态类。我添加了一个单独的条目来描述静态方法。谢谢你的收获。 'Object' 在这里谈论 C# 时可能不是一个好词,因为所有类的基本类型都是 System.Object。 “实例”会是一个更好的词,或者“对象”(小写“O”)。 @lesderid 'object' 是 'System.Object' 的别名,使用它也可能会造成混淆。 'instance' 会更好,我猜 :) 同样的规则适用于结构。【参考方案4】:转发来自this answer 的精彩图表。
这里是维恩图中的所有访问修饰符,从更多限制到更混杂:
private
:
private protected
: - added in C# 7.2
internal
:
protected
:
protected internal
:
public
:
【讨论】:
【参考方案5】:当前access modifier (C# 7.2) 的另一种可视化方法。希望架构有助于更轻松地记住它(单击图像以查看交互式视图。)
外面里面
如果您难以记住两个词的访问修饰符,请记住 outside-inside。
private protected:private outside(同一个程序集)protected inside(同一个程序集) ) 受保护的内部:受保护 外部(相同的程序集)内部 内部(相同的程序集)【讨论】:
【参考方案6】:using System;
namespace ClassLibrary1
public class SameAssemblyBaseClass
public string publicVariable = "public";
protected string protectedVariable = "protected";
protected internal string protected_InternalVariable = "protected internal";
internal string internalVariable = "internal";
private string privateVariable = "private";
public void test()
// OK
Console.WriteLine(privateVariable);
// OK
Console.WriteLine(publicVariable);
// OK
Console.WriteLine(protectedVariable);
// OK
Console.WriteLine(internalVariable);
// OK
Console.WriteLine(protected_InternalVariable);
public class SameAssemblyDerivedClass : SameAssemblyBaseClass
public void test()
SameAssemblyDerivedClass p = new SameAssemblyDerivedClass();
// NOT OK
// Console.WriteLine(privateVariable);
// OK
Console.WriteLine(p.publicVariable);
// OK
Console.WriteLine(p.protectedVariable);
// OK
Console.WriteLine(p.internalVariable);
// OK
Console.WriteLine(p.protected_InternalVariable);
public class SameAssemblyDifferentClass
public SameAssemblyDifferentClass()
SameAssemblyBaseClass p = new SameAssemblyBaseClass();
// OK
Console.WriteLine(p.publicVariable);
// OK
Console.WriteLine(p.internalVariable);
// NOT OK
// Console.WriteLine(privateVariable);
// Error : 'ClassLibrary1.SameAssemblyBaseClass.protectedVariable' is inaccessible due to its protection level
//Console.WriteLine(p.protectedVariable);
// OK
Console.WriteLine(p.protected_InternalVariable);
using System;
using ClassLibrary1;
namespace ConsoleApplication4
class DifferentAssemblyClass
public DifferentAssemblyClass()
SameAssemblyBaseClass p = new SameAssemblyBaseClass();
// NOT OK
// Console.WriteLine(p.privateVariable);
// NOT OK
// Console.WriteLine(p.internalVariable);
// OK
Console.WriteLine(p.publicVariable);
// Error : 'ClassLibrary1.SameAssemblyBaseClass.protectedVariable' is inaccessible due to its protection level
// Console.WriteLine(p.protectedVariable);
// Error : 'ClassLibrary1.SameAssemblyBaseClass.protected_InternalVariable' is inaccessible due to its protection level
// Console.WriteLine(p.protected_InternalVariable);
class DifferentAssemblyDerivedClass : SameAssemblyBaseClass
static void Main(string[] args)
DifferentAssemblyDerivedClass p = new DifferentAssemblyDerivedClass();
// NOT OK
// Console.WriteLine(p.privateVariable);
// NOT OK
//Console.WriteLine(p.internalVariable);
// OK
Console.WriteLine(p.publicVariable);
// OK
Console.WriteLine(p.protectedVariable);
// OK
Console.WriteLine(p.protected_InternalVariable);
SameAssemblyDerivedClass dd = new SameAssemblyDerivedClass();
dd.test();
【讨论】:
我看不出这个答案比过去五年的许多其他答案增加了什么。 这只是一个简单的解释。由于其他答案有点混乱,回答了一半:) @John Saunders:它通过区分派生类的可见性来区分该类在同一个程序集中和该类在不同程序集中。另外,他通过展示他的示例代码提供了他是如何获得这些信息的。所以它实际上增加了其他答案。他的死灵术可能是由我在回答中的评论触发的。 “不同程序集中的派生类” - 这为另一个答案中已经给出的图表增加了价值。这种差异很有帮助,尤其是在“受保护的内部”的情况下 我发现这张图表对我来说是最容易理解的。为了保持这个最新(使用 C# 7.2),添加Private Protected
,它将是:相同的 class= Yes
,相同的程序集,派生的 class= Yes
,相同的程序集,任何 class= NO
,不同的程序集,派生 class= NO
,不同的程序集,任何 class= NO
。还有一个建议是不要切换protected internal
的词序,因为这会破坏@user1810087 的答案【参考方案7】:
关于Nothing
的问题 命名空间类型默认是内部的 任何类型成员,包括嵌套类型,默认都是私有的【讨论】:
【参考方案8】:嗯。
请看这里:Access Modifiers。
简而言之:
Public 使方法或类型从其他类型/类中完全可见。
Private 只允许包含私有方法/变量的类型访问私有方法/变量(注意嵌套类也可以访问包含类的私有方法/变量)。
Protected 类似于 private,只是派生类也可以访问受保护的方法。
“Nothing”在 VB.NET 中等同于 null。尽管如果您指的是“无”,意思是“没有访问修饰符”,那么这取决于,尽管一个非常粗略的经验法则(当然在 C# 中)是,如果您没有显式指定访问修饰符,则方法/变量声明通常尽可能受限。 即
public class MyClass
string s = "";
实际上等同于:
public class MyClass
private string s = "";
链接的 MSDN 文章将在没有明确指定访问修饰符时提供完整描述。
【讨论】:
【参考方案9】:public - 任何地方的任何人都可以访问。private - 只能从它所属的类中访问。protected - 只能从类中的 with 或从该类继承的任何对象中访问。
在 VB 中,没有什么比 null 更重要了。 静态意味着您拥有该对象的一个实例,该类的每个实例的方法。
【讨论】:
【参考方案10】:嗯……
静态意味着您可以在没有类实例的情况下访问该函数。
您可以直接从类定义中访问。
【讨论】:
【参考方案11】:Private 状态表示变量只能被同一类的对象访问。受保护状态将访问权限扩展到包括该类的后代。
“从上表中我们可以看到私有和受保护之间的区别......我认为两者都是相同的......所以需要这两个单独的命令”
查看MSDN链接了解更多信息
【讨论】:
【参考方案12】:这些访问修饰符指定您的成员在哪里可见。您可能应该阅读此内容。以 IainMH 给出的链接为起点。
静态成员每个类一个,而不是每个实例一个。
【讨论】:
【参考方案13】:小心!观看您的课程的可访问性。默认情况下,所有人都可以访问公共和受保护的类和方法。
此外,在 Visual Studio 中创建新类时,Microsoft 在显示访问修饰符(public、protected 等关键字)方面并不是很明确。因此,请注意并考虑您的类的可访问性,因为它是您实现内部的大门。
【讨论】:
【参考方案14】:我认为这与良好的 OOP 设计有关。如果你是一个库的开发者,你想隐藏你的库的内部工作。这样,您可以稍后修改您的库内部工作。所以你把你的成员和辅助方法设置为私有的,只有接口方法是公共的。应该被覆盖的方法应该受到保护。
【讨论】:
【参考方案15】:C# 总共有 6 个访问修饰符:
private:使用此可访问性声明的成员可以在包含类型中可见,它对任何派生类型、同一程序集中的其他类型或包含程序集之外的类型均不可见。即,访问仅限于包含类型。
protected:使用此可访问性声明的成员可以在从包含程序集内的包含类型派生的类型中可见,以及从包含程序集外部的包含类型派生的类型中可见。即,访问仅限于包含类型的派生类型。
internal:使用此可访问性声明的成员可以在包含此成员的程序集中可见,它对包含程序集之外的任何程序集都不可见。即,访问仅限于包含程序集。
internal protected:使用此可访问性声明的成员可以在从包含程序集内部或外部的包含类型派生的类型中可见,它也对包含程序集内的任何类型可见。即,访问仅限于包含程序集或派生类型。
public:使用此可访问性声明的成员可以在包含该成员的程序集中或引用包含该程序集的任何其他程序集中可见。即,访问不受限制。
在 C# 7.2 中,添加了新级别的可访问性:
private protected:使用此可访问性声明的成员可以在从包含程序集中的此包含类型派生的类型中可见。对于不是从包含类型派生的任何类型或在包含程序集之外的任何类型,它都是不可见的。即,访问仅限于包含程序集中的派生类型。
Source including a sample code of the new private protected access modifier
【讨论】:
【参考方案16】:public
表示它可以被任何程序集中的任何类访问,包括类本身。
protected internal
表示它可以被类本身访问(在类定义中),并且可以被当前程序集中的任何类访问,但在程序集之外它只能被继承该类的类访问,或通过类本身(如果它是部分类) - 基本上它意味着程序集内的 internal
和程序集外的 protected
。
protected
表示它只能由类本身访问,或者由继承它的类访问,并且该类可以在任何程序集中
internal
表示它可以由类本身或程序集中的任何类访问,但在程序集之外根本无法访问,除非由类本身(即它是一个部分类)
private protected
表示它只能由类本身访问,或者它可以由继承它的类访问,并且只有当该类在当前程序集中时才能访问。在程序集之外,它只能由类本身访问(即它是一个部分类)——基本上结合了internal
和protected
,或者另一种说法是它在程序集之外是private
和@ 987654332@ 在程序集中。
private
表示只能由类本身访问
无访问修饰符:The default access for everything in C# is "the most restricted access you could declare for that member".,对于类中的成员/方法/嵌套类是private
,对于非嵌套类是internal
。
在上面的文本中,“访问”意味着通过类类型的对象进行访问,在类本身的方法中,该对象将是隐式的 this
对象,或者该方法实例化了当前类类型的显式对象并通过该对象访问它。两者都被认为是由类本身访问的,因此访问规则是相同的。这也适用于从静态方法执行的访问,或者当它是被访问的静态成员/方法时,除了使用类范围而不是对象执行访问。静态类的成员/方法需要显式设置为static
,否则无法编译。
非嵌套类可以是public
或internal
,默认为internal
。嵌套的类可以是任何访问类型,如果父类是静态的,它不需要是静态的,它的成员也不需要。 internal
类意味着它只能被实例化,或者它的静态成员只能从当前程序集中访问。
您可以在internal
或private
嵌套类中拥有公共成员/方法/嵌套类——只有低于级别的访问说明符(在正在进行的访问的完全限定名称中)正在进行的当前访问中的 required 会阻止访问。
C#中的继承总是public
,不像C++,它可以私有或受保护地继承,然后改变所有类的访问权限,然后继承自该类的类,以及通过对象/通过从类中私有/受保护地继承的类的类型的类范围以及从私有/受保护地继承的类继承的类形成该类,依此类推。访问权限已更改,所有限制性低于private
或protected
的访问修饰符分别设为private
和protected
。
【讨论】:
【参考方案17】:C#的所有访问修饰符的描述
【讨论】:
以上是关于在 C# 中,public、private、protected 和没有访问修饰符有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章
php class中public,private,protected的区别,以及实例
封装何时胜过 SOLID - public vs private c# 类?
C#中的public protected internal private
c#用户控件定义了一个函数, private void dfd(), 我在窗口中生成一个用户控件,然后怎么调用这个函数