在C#中,公共、私有、受保护和没有访问修饰符有什么区别?

我所有的大学岁月我一直在使用public,想知道public之间的区别,private,和protected

与一无所有相比,static做了什么?

758734 次浏览

这些访问修饰符指定您的成员可见的位置。您可能应该仔细阅读这篇文章。以IainMH给出的链接为起点。

静态成员是每个类一个,而不是每个实例一个。

嗯…

静态意味着您可以在没有类实例的情况下访问该函数。

您可以直接从类定义访问。

嗯。

看这里:访问修饰符

简而言之:

Public使方法或类型完全可见于其他类型/类。

Private只允许包含私有方法/变量的类型访问私有方法/变量(注意嵌套类也可以访问包含类的私有方法/变量)。

受保护的类似于私有,除了派生类也可以访问受保护的方法。

"无"VB.NET相当于null。虽然如果你指的是"无"的意思是"没有访问修饰符",那么这取决于,尽管一个非常粗略的经验法则(当然在C#中)是,如果你没有显式指定访问修饰符,方法/变量声明通常尽可能限制。即

public class MyClass{string s = "";}

实际上是相同的:

public class MyClass{private string s = "";}

当没有显式指定访问修饰符时,链接的MSDN文章将提供完整的描述。

访问修饰符

learn.microsoft.com

public

同一程序集中的任何其他代码或引用它的另一个程序集中的任何其他代码都可以访问该类型或成员。

private

类型或成员只能由同一类或结构中的代码访问。

protected

类型或成员只能由同一类或结构或派生类中的代码访问。

#0(在C#7.2中添加)

只能通过同一类或结构中的代码或来自同一程序集的派生类中的代码访问类型或成员,但不能从另一个程序集访问。

internal

同一程序集中的任何代码都可以访问该类型或成员,但不能从另一个程序集中访问。

protected internal

同一程序集中的任何代码或另一个程序集中的任何派生类都可以访问该类型或成员。

当设置无访问修饰符时,使用默认的访问修饰符。所以即使没有设置,也总是有某种形式的访问修饰符。

static修饰符

类的静态修饰符意味着这个类不能被实例化,并且它的所有成员都是静态的。无论创建了多少个其封闭类型的实例,静态成员都有一个版本。

静态类与非静态类基本相同,但有一个区别:静态类不能外部实例化。换句话说,您不能使用new关键字创建类类型的变量。因为没有实例变量,所以您使用类名本身访问静态类的成员。

然而,有一个静态构造函数这样的东西。任何类都可以有其中之一,包括静态类。它们不能直接调用&不能有参数(类本身的任何类型参数除外)。在创建第一个实例或引用任何静态成员之前,会自动调用静态构造函数来初始化类。看起来像这样:

static class Foo(){static Foo(){Bar = "fubar";}    
public static string Bar { get; set; }}

静态类通常用作服务,你可以这样使用它们:

MyStaticClass.ServiceMethod(...);

公共-任何地方的任何人都可以访问。
私人-只能从它所属的类中的with访问。
protected-只能从类中的with或从类继承的任何对象访问。

除了在VB中,没有什么像null。
静态意味着你有一个该对象的实例,该类的每个实例的方法。

我认为这与良好的面向对象设计有关。如果你是一个库的开发人员,你想隐藏你的库的内部工作方式。这样,你可以稍后修改你的库内部工作方式。所以你把你的成员和辅助方法设置为私有,只有接口方法是公共的。应该覆盖的方法应该受到保护。

小心!注意类的可访问性。默认情况下,每个人都可以访问公共和受保护的类和方法。

此外,当在Visual Studio中创建新类时,Microsoft在显示访问修饰符(public、protected等…关键字)方面并不是非常明确。因此,请小心并考虑您的类的可访问性,因为它是通往您的实现内部的大门。

公共-如果你能看到类,那么你就能看到方法

私人-如果你是类的的一部分,那么你可以看到方法,否则不能。

保护-与Private相同,加上所有后代也可以看到该方法。

静态(类)-还记得“类”和“对象”之间的区别吗?忘记所有这些。它们与“静态”相同…类是自身的唯一实例。

静态(方法)-无论何时使用此方法,它都将具有独立于它所属类的实际实例的参考框架。

关于什么都没有的问题

  • 命名空间类型默认是内部的
  • 默认情况下,任何类型成员(包括嵌套类型)都是私有的

状态为Private表示变量只能由同一类的对象访问。受保护状态将该访问扩展到包括类的后代。

“从上表中我们可以看到私有和受保护之间的差异……我认为两者都是一样的……那么这两个单独的命令需要什么?”

查看MSDN链接了解更多信息

图形概述(简而言之)

可见性

实际上,它比这更复杂一点。
现在(从C#7.2开始),还有私有保护,派生类是否在同一个程序集中很重要。

因此,概述需要扩展:

可见性扩展

另见关于主题的C#-dotnet-docs

由于静态类是密封的,它们不能被继承(除了从Object),因此关键字protected在静态类上无效。



如果您在前面没有放置访问修饰符,则默认值请参见此处:
C#类和成员(字段、方法等)的默认可见性?

非嵌套

enum                              publicnon-nested classes / structs      internalinterfaces                        internaldelegates in namespace            internalclass/struct member(s)            privatedelegates nested in class/struct  private

嵌套:

nested enum      publicnested interface publicnested class     privatenested struct    private

此外,还有一个密封关键字,它使类不可继承。
此外,在VB.NET,关键字有时是不同的,所以这里有一个备忘单:

VB vs. CS等效

输入图片描述

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(){// OKConsole.WriteLine(privateVariable);
// OKConsole.WriteLine(publicVariable);
// OKConsole.WriteLine(protectedVariable);
// OKConsole.WriteLine(internalVariable);
// OKConsole.WriteLine(protected_InternalVariable);}}
public class SameAssemblyDerivedClass : SameAssemblyBaseClass{public void test(){SameAssemblyDerivedClass p = new SameAssemblyDerivedClass();
// NOT OK// Console.WriteLine(privateVariable);
// OKConsole.WriteLine(p.publicVariable);
// OKConsole.WriteLine(p.protectedVariable);
// OKConsole.WriteLine(p.internalVariable);
// OKConsole.WriteLine(p.protected_InternalVariable);}}
public class SameAssemblyDifferentClass{public SameAssemblyDifferentClass(){SameAssemblyBaseClass p = new SameAssemblyBaseClass();
// OKConsole.WriteLine(p.publicVariable);
// OKConsole.WriteLine(p.internalVariable);
// NOT OK// Console.WriteLine(privateVariable);
// Error : 'ClassLibrary1.SameAssemblyBaseClass.protectedVariable' is inaccessible due to its protection level//Console.WriteLine(p.protectedVariable);
// OKConsole.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);
// OKConsole.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);
// OKConsole.WriteLine(p.publicVariable);
// OKConsole.WriteLine(p.protectedVariable);
// OKConsole.WriteLine(p.protected_InternalVariable);
SameAssemblyDerivedClass dd = new SameAssemblyDerivedClass();dd.test();}}}

C#总共有6个访问修饰符:

私人:使用此可访问性声明的成员可以在包含类型内可见,它对任何派生类型、同一程序集中的其他类型或包含程序集之外的类型都不可见。即,访问仅限于包含类型。

保护:使用此可访问性声明的成员可以在包含程序集中从包含类型派生的类型内可见,并且在包含程序集中之外从包含类型派生的类型可见。即,访问仅限于包含类型的派生类型。

内部:使用此可访问性声明的成员可以在包含此成员的程序集中可见,它对包含程序集之外的任何程序集都不可见。即,访问仅限于包含程序集。

内部保护:使用此可访问性声明的成员可以在从包含程序集内部或外部的包含类型派生的类型内可见,它也对包含程序集内的任何类型可见。即,访问仅限于包含程序集或派生类型。

公共:使用此可访问性声明的成员可以在包含此成员的程序集中可见,或者引用包含该程序集的任何其他程序集中可见。即,访问不受限制。

在C#7.2中,添加了一个新的可访问性级别:

私人保护:具有此可访问性声明的成员可以在包含程序集中派生自此包含类型的类型内可见。它对任何非派生自包含类型的类型或包含程序集外部的类型不可见。即,访问仅限于包含程序集中的派生类型。

包含新的私有保护访问修饰符的示例代码的源代码

重新发布来自这个答案的令人敬畏的图表。

以下是维恩图中的所有访问修饰符,从更具限制性到更混杂:

private
在此处输入图片描述

private protected:-在C#7.2中添加
在此处输入图片描述

internal
在此处输入图片描述

protected
在此处输入图片描述

protected internal
在此处输入图片描述

public
在此处输入图片描述

当前访问修饰符(C#7.2)的另一种可视化方法。希望模式有助于更容易记住它
(单击图像进行交互查看。)

交互式访问修饰符svg

外面里面

如果你很难记住两个词的访问修饰符,请记住<强>外-内

  • 私人保护私人外面(相同组件)保护里面(相同组件)
  • 保护内部保护外面(相同组件)内部里面(相同组件)

C#的所有访问修饰符描述

在此处输入图片描述

  • public意味着它可以被任何程序集中的任何类访问,包括类本身。
  • protected internal意味着它可以被类本身访问(在类定义中),并且它可以被当前程序集中的任何类访问,但是在程序集之外,它只能被继承该类的类访问,或者被类本身访问(如果它是一个部分类)-基本上它意味着internal在程序集中,protected在程序集之外。
  • protected意味着它只能被类本身访问,或者被继承它的类访问,该类可以在任何程序集中
  • internal意味着它可以被类本身或程序集中的任何类访问,但不能在程序集之外访问,除非由类本身(即它是一个部分类)
  • private protected表示它只能被类本身访问,或者它可以被继承它的类访问,并且只有当该类在当前程序集中时。在程序集之外,它只能被类本身访问(即它是一个部分类)-基本上结合了internalprotected,或者换句话说,它在程序集之外是private,在程序集中是protected
  • private表示只能由类本身访问
  • 无访问修饰符:C#中所有内容的默认访问权限是“您可以为该成员声明的最受限制的访问权限”。,对于类中的成员/方法/嵌套类为private,对于非嵌套类为internal

在上面的文字中,“被访问”是指通过类类型的对象访问,该对象在类的方法本身中将是隐式的this对象,或者该方法实例化当前类类型的一个显式对象并通过该对象访问它。两者都被认为是类本身访问的,因此访问规则是相同的。这也适用于从静态方法执行的访问,或者当它是被访问的静态成员/方法时,除了访问是使用类范围而不是对象执行的。静态类的成员/方法需要显式地制作static,否则它不会编译。

未嵌套的类可以是publicinternal,默认情况下是internal。嵌套的类可以是任何存取类型,如果父类是静态的,则不需要是静态的,其成员也不需要。internal类意味着它只能实例化或从当前程序集访问其静态成员。

您可以在internalprivate嵌套类中拥有公共成员/方法/嵌套类-只有低于当前访问所需级别的访问说明符(在正在进行的访问的完全限定名称中)才能阻止访问。

与C++不同,C#中的继承总是public,它可以私下或保护地继承,然后更改然后从该类继承的类的所有类的访问,以及通过对象/通过类范围的访问从私有/保护地继承的类和从私有/保护地继承的类继承的类形成类的类的类型,依此类推。访问被更改,使得所有限制小于privateprotected的访问修饰符分别变为privateprotected

我已经创建了另一种类型的可视化。也许这可以更好地理解的人

https://github.com/TropinAlexey/C-sharp-Access-Modifiers

输入图片描述

公共同一程序集中的任何其他代码或引用它的另一个程序集中的任何其他代码都可以访问该类型或成员。类型的公共成员的可访问性级别由类型本身的可访问性级别控制。

私人类型或成员只能由同一类或结构中的代码访问。

内部内部类型或成员只能在同一程序集中的文件中访问。

保护类型或成员只能由同一类中的代码或从该类派生的类中的代码访问。内部:同一程序集中的任何代码都可以访问类型或成员,但不能从另一个程序集中访问。换句话说,内部类型或成员可以从属于同一编译的代码中访问。受保护的内部:类型或成员可以被声明它的程序集中的任何代码访问,也可以从另一个程序集中的派生类中访问。

私人保护类型或成员可以由派生自在其包含程序集中声明的类的类型访问。

保护内部可以从当前程序集或从包含类派生的类型访问受保护的内部成员。

静态修饰符用于声明静态成员,该成员属于类型本身而不是特定对象。静态修饰符可用于声明静态类。在类、接口和结构中,您可以将静态修饰符添加到字段、方法、属性、运算符、事件和构造函数中。

对于c文件1,您还可以使用文件访问修饰符。

文件修饰符将顶级类型的范围和可见性限制在声明它的文件中。文件修饰符通常应用于源生成器编写的类型。文件本地类型为源生成器提供了一种方便的方法来避免生成的类型之间的名称冲突。

// In File1.cs:file interface IWidget{int ProvideAnswer();}
file class HiddenWidget{public int Work() => 42;}
public class Widget : IWidget{public int ProvideAnswer(){var worker = new HiddenWidget();return worker.Work();}}