提问人:MrM 提问时间:3/5/2009 最后编辑:neaumusicMrM 更新时间:5/30/2023 访问量:786113
在 C# 中,public、private、protected 和 having no access 修饰符之间有什么区别?
In C#, what is the difference between public, private, protected, and having no access modifier?
问:
我所有的大学时代我一直在使用 ,并想知道 、 和 之间的区别?public
public
private
protected
另外,与一无所有相比,做什么是什么?static
答:
这些访问修饰符指定成员的可见位置。你可能应该读一读这篇文章。以 IainMH 提供的链接为起点。
静态成员是每个类一个,而不是每个实例一个。
嗯。。。
静态意味着您可以在没有类实例的情况下访问该函数。
您可以直接从类定义进行访问。
嗯。
请参阅此处:访问修饰符。
简而言之:
Public 使方法或类型与其他类型/类完全可见。
Private 只允许包含私有方法/变量的类型访问私有方法/变量(请注意,嵌套类也可以访问包含的类私有方法/变量)。
protected 类似于 private,只是派生类也可以访问受保护的方法。
“Nothing”是 VB。NET 等效于 null。尽管如果您指的是“nothing”,即“无访问修饰符”,那么这取决于,尽管一个非常粗略的经验法则(当然在 C# 中)是,如果您不显式指定访问修饰符,则方法/变量声明通常会受到尽可能的限制。 即
public class MyClass
{
string s = "";
}
实际上与以下相同:
public class MyClass
{
private string s = "";
}
链接的 MSDN 文章将在未显式指定访问修饰符时提供完整的说明。
访问修饰符
类型或成员可由同一程序集中的任何其他代码或引用它的其他程序集中的任何其他代码访问。
类型或成员只能由同一类或结构中的代码访问。
类型或成员只能由同一类或结构或派生类中的代码访问。
私有保护
(在 C# 7.2 中添加)类型或成员只能由同一类或结构中的代码访问,或者只能由同一程序集的派生类中的代码访问,而不能从另一个程序集访问。
类型或成员可以由同一程序集中的任何代码访问,但不能从另一个程序集访问。
类型或成员可以由同一程序集中的任何代码访问,也可以由另一个程序集中的任何派生类访问。
如果未设置访问修饰符,则使用默认访问修饰符。因此,即使没有设置,也总是有某种形式的访问修饰符。
静态
修饰符
类的 static 修饰符意味着该类不能实例化,并且其所有成员都是静态的。静态成员具有一个版本,无论创建了多少个其封闭类型的实例。
静态类与非静态类基本相同,但有一个区别:静态类不能在外部实例化。换言之,不能使用 new 关键字创建类类型的变量。由于没有实例变量,因此可以使用类名本身访问静态类的成员。
但是,有一种静态构造函数。任何类都可以具有其中之一,包括静态类。它们不能直接调用,也不能有参数(除了类本身的任何类型参数)。在创建第一个实例或引用任何静态成员之前,会自动调用静态构造函数来初始化类。看起来像这样:
static class Foo()
{
static Foo()
{
Bar = "fubar";
}
public static string Bar { get; set; }
}
静态类通常用作服务,您可以像这样使用它们:
MyStaticClass.ServiceMethod(...);
评论
protected
private protected
公共 - 任何人都可以在任何地方访问。
private - 只能从它所属的类中的 with 访问。
受保护 - 只能从类中的 with 或从类继承的任何对象访问。
除了在 VB 中,没有什么是像 null 一样的。 静态意味着您有一个该对象的实例,该类的每个实例的方法。
我认为这与良好的OOP设计有关。如果您是库的开发人员,则希望隐藏库的内部工作原理。这样,您以后就可以修改库的内部工作原理。因此,您将成员和帮助程序方法设置为私有方法,并且只有接口方法是公共的。应覆盖的方法应受到保护。
小心!注意课程的可访问性。默认情况下,每个人都可以访问公共和受保护的类和方法。
此外,在 Visual Studio 中创建新类时,Microsoft 在显示访问修饰符(public、protected 等关键字)方面并不是很明确。因此,请小心并考虑您的类的可访问性,因为它是通往实现内部的大门。
Public - 如果可以看到类,则可以看到方法
私有 - 如果你是类的一部分,那么你可以看到方法,否则就看不到。
受保护 - 与“私有”相同,此外,所有后代也可以看到该方法。
静态(类) - 还记得“类”和“对象”之间的区别吗?忘掉这一切。它们与“静态”相同......类是其自身的唯一实例。
静态(方法) - 每当使用此方法时,它都会有一个独立于它所属类的实际实例的引用框架。
评论
关于“无”的问题
- 默认情况下,命名空间类型是内部的
- 默认情况下,任何类型成员(包括嵌套类型)都是私有的
状态为 Private 表示变量只能由同一类的对象访问。受保护状态扩展了该访问权限,以包括该类的后代。
“从上表中,我们可以看到私人和受保护之间的尊重......我认为两者都是一样的......那么需要这两个单独的命令吗”
有关详细信息,请查看 MSDN 链接
图形概述(简明扼要)
实际上,它比这要复杂一些。
现在(从 C# 7.2 开始),还有私有保护,派生类是否在同一个程序集中很重要。
因此,需要扩展概述:
由于静态类是密封的,因此它们不能被继承(除了从 Object 继承),因此关键字 protected 在静态类上无效。
对于在前面放置无访问修饰符的默认值,请参阅此处:
C# 类和成员(字段、方法等)的默认可见性?
非嵌套
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
此外,还有 sealed-keyword,它使类不可继承。
此外,在 VB.NET 中,关键字有时是不同的,所以这里有一个备忘单:
评论
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();
}
}
}
评论
Private Protected
Yes
Yes
NO
NO
NO
protected internal
C# 总共有 6 个访问修饰符:
private:使用此辅助功能声明的成员可以在包含类型中可见,对任何派生类型、同一程序集中的其他类型或包含程序集外部的类型都不可见。即,访问仅限于包含类型。
protected:使用此辅助功能声明的成员可以在从包含程序集中的包含类型派生的类型中可见,也可以在从包含程序集外部的包含类型派生的类型中可见。即,访问仅限于包含类型的派生类型。
internal:使用此可访问性声明的成员可以在包含此成员的程序集中可见,对包含程序集之外的任何程序集都不可见。即,访问仅限于包含程序集。
内部保护:使用此可访问性声明的成员可以在包含程序集内部或外部的包含类型派生的类型中可见,它对包含程序集中的任何类型也可见。即,访问仅限于包含程序集或派生类型。
public:使用此辅助功能声明的成员可以在包含此成员的程序集中可见,也可以在引用包含程序集的任何其他程序集中可见。即,访问不受限制。
在 C# 7.2 中,添加了新的可访问性级别:
private protected:使用此辅助功能声明的成员可以在包含程序集中从此包含类型派生的类型中可见。它对任何不是从包含类型派生的类型或包含程序集外部的类型都不可见。即,访问仅限于包含程序集中的派生类型。
重新发布此答案中的精彩图表。
以下是维恩图中的所有访问修饰符,从更限制到更混杂:
private
:
private protected
: - 在 C# 7.2 中添加
internal
:
protected
:
protected internal
:
public
:
当前访问修饰符的另一种可视化方法 (C# 7.2)。希望该架构有助于更轻松地
记住它(单击图像可查看交互式视图。
由外而内
如果您难以记住两个单词的访问修饰符,请记住由外到内。
- 私有保护:外部私有(同一程序集) 内部受保护(同一程序集)
- 受保护的内部:外部受保护(同一组件) 内部 受保护(同一组件)
C 的所有访问修饰符的描述#
public
意味着它可以由任何程序集中的任何类访问,其中包括类本身。protected internal
意味着它可以由类本身(在类定义中)访问,并且可以由当前程序集中的任何类访问,但在程序集之外,它只能由继承该类的类或类本身(如果它是分部类)访问——基本上它意味着程序集内部和程序集外部。internal
protected
protected
表示它只能由类本身访问,或者由继承它的类访问,并且该类可以位于任何程序集中internal
表示它可以由类本身或程序集中的任何类访问,但除非类本身(即它是一个分部类),否则在程序集外部根本无法访问private protected
表示它只能由类本身访问,或者只能由继承它的类访问,并且仅当该类位于当前程序集中时才能访问它。在程序集之外,它只能由类本身访问(即它是一个分部类)——基本上是组合和 ,或者另一种说法是它在程序集外部和程序集内部。internal
protected
private
protected
private
意味着它只能由类本身访问- 无访问修饰符:C# 中所有内容的默认访问权限是“您可以为该成员声明的最受限制的访问”,即针对类中的成员/方法/嵌套类和非嵌套类。
private
internal
在上面的文本中,“访问”是指通过类类型的对象访问,该对象在类本身的方法中将是隐式对象,或者该方法实例化当前类类型的显式对象并通过该对象访问它。两者都被视为由类本身访问,因此访问规则是相同的。这也适用于从静态方法执行的访问,或者当它是被访问的静态成员/方法时,除非访问是使用类作用域而不是 and object 执行的。静态类的成员/方法需要显式创建,否则将无法编译。this
static
默认情况下,未嵌套的类可以是 or 和 are。嵌套的类可以是任何访问类型,如果父类是静态的,则它不需要是静态的,其成员也不需要是静态的。类意味着它只能实例化或从当前程序集访问其静态成员。public
internal
internal
internal
可以在一个或嵌套类中有一个公共成员/方法/嵌套类 -- 只有访问说明符(在所进行的访问的完全限定名称中)低于当前所进行的访问所需的级别才能阻止访问。internal
private
C# 中的继承始终与 C++不同,后者可以私下或受保护地继承,然后更改所有类的访问,然后从从该类继承的类继承,以及通过对象/通过类范围访问从该类私下/受保护地继承的类的类和从私下/受保护地继承的类的类的类型范围进行访问。 等等。更改访问,使得所有访问修饰符的限制性都小于 或 和 分别。public
private
protected
private
protected
我创建了另一种类型的可视化。也许这对某人来说可以是更好的理解方式
https://github.com/TropinAlexey/C-sharp-Access-Modifiers
公共类型或成员可由同一程序集中的任何其他代码或引用它的其他程序集中的任何其他代码访问。类型的公共成员的可访问性级别由类型本身的可访问性级别控制。
私人类型或成员只能由同一类或结构中的代码访问。
内部内部类型或成员只能在同一程序集中的文件中访问。
保护类型或成员只能由同一类中的代码或从该类派生的类中的代码访问。 internal:类型或成员可以由同一程序集中的任何代码访问,但不能从另一个程序集访问。换言之,可以从属于同一编译的代码访问内部类型或成员。 受保护的内部:类型或成员可由声明该类型或成员的程序集中的任何代码访问,也可以从另一个程序集的派生类中访问。
私人保护类型或成员可以通过派生自类的类型来访问,这些类型在其包含的程序集中声明。
受保护的内部受保护的内部成员可从当前程序集或从包含类派生的类型进行访问。
static 修饰符用于声明静态成员,该成员属于类型本身,而不是特定对象。static 修饰符可用于声明静态类。在类、接口和结构中,您可以将 static 修饰符添加到字段、方法、属性、运算符、事件和构造函数中。
文件修饰符将顶级类型的范围和可见性限制为声明该类型的文件。文件修饰符通常应用于源生成器编写的类型。文件本地类型为源生成器提供了一种方便的方法,可以避免生成的类型之间发生名称冲突。
// 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();
}
}
鉴于 Stack Exchange 中的所有站点(包括 Stack Overflow)现在都支持 Markdown 表,我在这里缺少一个答案。
汇总表:
来电者的位置 | 公共 | 受保护的内部 | 保护 | 内部 | 私人保护 | 私人 |
---|---|---|---|---|---|---|
在班级内 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
派生类(同一程序集) | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ❌ |
非派生类(同一程序集) | ✔️ | ✔️ | ❌ | ✔️ | ❌ | ❌ |
派生类(不同的程序集) | ✔️ | ✔️ | ✔️ | ❌ | ❌ | ❌ |
非派生类(不同的程序集) | ✔️ | ❌ | ❌ | ❌ | ❌ | ❌ |
源:
https://meta.stackexchange.com/questions/356997/new-feature-table-support
评论