在 C# 中,public、private、protected 和 having no access 修饰符之间有什么区别?

In C#, what is the difference between public, private, protected, and having no access modifier?

提问人:MrM 提问时间:3/5/2009 最后编辑:neaumusicMrM 更新时间:5/30/2023 访问量:786113

问:

我所有的大学时代我一直在使用 ,并想知道 、 和 之间的区别?publicpublicprivateprotected

另外,与一无所有相比,做什么是什么?static

C# .NET asp.net 访问修饰符

评论


答:

3赞 jpfollenius 3/5/2009 #1

这些访问修饰符指定成员的可见位置。你可能应该读一读这篇文章。以 IainMH 提供的链接为起点。

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

5赞 gbianchi 3/5/2009 #2

嗯。。。

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

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

12赞 CraigTP 3/5/2009 #3

嗯。

请参阅此处:访问修饰符

简而言之:

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

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

protected 类似于 private,只是派生类也可以访问受保护的方法。

“Nothing”是 VB。NET 等效于 null。尽管如果您指的是“nothing”,即“无访问修饰符”,那么这取决于,尽管一个非常粗略的经验法则(当然在 C# 中)是,如果您不显式指定访问修饰符,则方法/变量声明通常会受到尽可能的限制。 即

public class MyClass
{
    string s = "";
}

实际上与以下相同:

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

链接的 MSDN 文章将在未显式指定访问修饰符时提供完整的说明。

1090赞 mbillard 3/5/2009 #4

访问修饰符

learn.microsoft.com

public

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

private

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

protected

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

私有保护(在 C# 7.2 中添加)

类型或成员只能由同一类或结构中的代码访问,或者只能由同一程序集的派生类中的代码访问,而不能从另一个程序集访问。

internal

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

protected internal

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

如果未设置访问修饰符,则使用默认访问修饰符。因此,即使没有设置,也总是有某种形式的访问修饰符。

静态修饰符

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

静态类与非静态类基本相同,但有一个区别:静态类不能在外部实例化。换言之,不能使用 new 关键字创建类类型的变量。由于没有实例变量,因此可以使用类名本身访问静态类的成员。

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

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

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

MyStaticClass.ServiceMethod(...);

评论

19赞 John B 3/6/2009
你可以在非静态类中使用静态方法,对吧?
15赞 mbillard 3/6/2009
是的,它们的行为方式与我的示例相同。
9赞 Jonathan Gleason 12/11/2014
在这种情况下,“组装”一词是什么意思?
3赞 goofyui 7/12/2018
Protected 和 Private Protected 和有什么不一样?对我来说,听起来两者都是一样的。
2赞 Paul Smith 1/17/2020
@goofyui,区别在于成员可以在任何程序集的派生类中访问。 成员只能在同一程序集的派生类中访问。protectedprivate protected
12赞 Tony 3/5/2009 #5

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

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

3赞 Darius Kucinskas 3/5/2009 #6

我认为这与良好的OOP设计有关。如果您是库的开发人员,则希望隐藏库的内部工作原理。这样,您以后就可以修改库的内部工作原理。因此,您将成员和帮助程序方法设置为私有方法,并且只有接口方法是公共的。应覆盖的方法应受到保护。

4赞 Patrick Peters 3/5/2009 #7

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

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

167赞 JosephStyons 3/5/2009 #8

Public - 如果可以看到类,则可以看到方法

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

受保护 - 与“私有”相同,此外,所有后代也可以看到该方法。

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

静态(方法) - 每当使用此方法时,它都会有一个独立于它所属类的实际实例的引用框架。

评论

1赞 John B 3/6/2009
但是,你不能在非静态类中有静态方法吗?
1赞 JosephStyons 3/6/2009
是的,但我说的是静态类。我添加了一个单独的条目来描述静态方法。谢谢你的收获。
2赞 lesderid 7/16/2012
在谈论 C# 时,“Object”可能不是一个好术语,因为所有类的基类型都是 System.Object。“实例”或“对象”(小写“O”)会更好。
0赞 kazinix 7/5/2013
@lesderid“object”是“System.Object”的别名,使用它也可能令人困惑。“实例”会更好,我想:)
0赞 gsharp 7/18/2014
同样的规则也适用于结构。
23赞 leppie 3/6/2009 #9

关于“无”的问题

  • 默认情况下,命名空间类型是内部的
  • 默认情况下,任何类型成员(包括嵌套类型)都是私有的
5赞 Grant Hood 7/7/2010 #10

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

“从上表中,我们可以看到私人和受保护之间的尊重......我认为两者都是一样的......那么需要这两个单独的命令吗”

有关详细信息,请查看 MSDN 链接

206赞 Stefan Steiger 4/11/2014 #11

图形概述(简明扼要)

Visibility

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

因此,需要扩展概述:

Visibility expanded

另请参阅有关该主题的 C#-dotnet-docs

由于静态类是密封的,因此它们不能被继承(除了从 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 中,关键字有时是不同的,所以这里有一个备忘单:

VB vs. CS equivalents

评论

1赞 Stefan Steiger 1/8/2015
@ᴀʀᴜn BᴇrtiL:你确定吗?不同程序集中的派生类?
0赞 Arun Bertil 1/8/2015
派生类在同一个程序集中我们可以,不同的我们不能。我以为你的意思是像在同一个集会中......
1赞 Stefan Steiger 4/21/2015
@ᴀʀᴜn BᴇrtiL:嗯,对了,这实际上应该被孵化出来。
1赞 AH. 10/6/2016
我认为图中有一个错误。如果 internal 用于某个类,则该类可以由同一程序集中的另一个类派生。此外,如果在属性上使用 internal 修饰符,则也可以在同一程序集的派生类中访问此属性。也许该图是正确的,因为“包含程序集”下有一个“是”,但它可能会被误解,因为“派生类”下有一个“否”。
26赞 Narottam Goyal 5/24/2015 #12

enter image description here

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();
        }
    }
}

评论

1赞 John Saunders 5/24/2015
我看不出这个答案在过去五年的许多其他答案中增加了什么。
4赞 Narottam Goyal 5/24/2015
这只是一个简单的解释。由于其他答案有点令人困惑,一半的答案:)
4赞 Stefan Steiger 7/8/2016
@John Saunders:它通过分离派生类的可见性来区分该类位于同一程序集中,而该类位于不同的程序集中。此外,他还通过展示他的示例代码提供了他如何获得这些信息。因此,它实际上增加了其他答案。他的死灵术可能是由我在回答中的评论引发的。
2赞 Nirman 1/25/2018
“不同程序集中的派生类” - 这为另一个答案中已经给出的图表增加了价值。这种差异很有帮助,尤其是在“受保护的内部”的情况下
0赞 Intrastellar Explorer 10/21/2019
我发现这张图表对我来说是最容易理解的。为了保持当前状态(使用 C# 7.2),要添加 ,它将是:相同的类 = 、相同的程序集、派生类 = 、相同的程序集、任何类 = 、不同的程序集、派生类 = 、不同的程序集、任何类 = 。另一个建议是不要将 的词序切换为 ,因为这会将 @user1810087 的答案中的肺打断Private ProtectedYesYesNONONOprotected internal
3赞 Baccata 12/20/2017 #13

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

private:使用此辅助功能声明的成员可以在包含类型中可见,对任何派生类型、同一程序集中的其他类型或包含程序集外部的类型都不可见。即,访问仅限于包含类型。

protected:使用此辅助功能声明的成员可以在从包含程序集中的包含类型派生的类型中可见,也可以在从包含程序集外部的包含类型派生的类型中可见。即,访问仅限于包含类型的派生类型。

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

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

public:使用此辅助功能声明的成员可以在包含此成员的程序集中可见,也可以在引用包含程序集的任何其他程序集中可见。即,访问不受限制。

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

private protected:使用此辅助功能声明的成员可以在包含程序集中从此包含类型派生的类型中可见。它对任何不是从包含类型派生的类型或包含程序集外部的类型都不可见。即,访问仅限于包含程序集中的派生类型。

源代码,包括新的专用受保护访问修饰符的示例代码

56赞 Paul 4/1/2018 #14

重新发布此答案中的精彩图表。

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

private:
enter image description here

private protected: - 在 C# 7.2 中添加
enter image description here

internal:
enter image description here

protected:
enter image description here

protected internal:
enter image description here

public:
enter image description here

39赞 user1810087 2/21/2019 #15

当前访问修饰符的另一种可视化方法 (C# 7.2)。希望该架构有助于更轻松地
记住它(单击图像可查看交互式视图。

interactive access modifiers svg

由外而内

如果您难以记住两个单词的访问修饰符,请记住由外到内

  • 私有保护外部私有(同一程序集) 内部受保护(同一程序集)
  • 受保护的内部外部受保护(同一组件) 内部 受保护(同一组件)
2赞 Soner from The Ottoman Empire 3/4/2020 #16

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

enter image description here

5赞 Lewis Kelsey 3/31/2021 #17
  • public意味着它可以由任何程序集中的任何类访问,其中包括类本身。
  • protected internal意味着它可以由类本身(在类定义中)访问,并且可以由当前程序集中的任何类访问,但在程序集之外,它只能由继承该类的类或类本身(如果它是分部类)访问——基本上它意味着程序集内部和程序集外部。internalprotected
  • protected表示它只能由类本身访问,或者由继承它的类访问,并且该类可以位于任何程序集中
  • internal表示它可以由类本身或程序集中的任何类访问,但除非类本身(即它是一个分部类),否则在程序集外部根本无法访问
  • private protected表示它只能由类本身访问,或者只能由继承它的类访问,并且仅当该类位于当前程序集中时才能访问它。在程序集之外,它只能由类本身访问(即它是一个分部类)——基本上是组合和 ,或者另一种说法是它在程序集外部和程序集内部。internalprotectedprivateprotected
  • private意味着它只能由类本身访问
  • 无访问修饰符:C# 中所有内容的默认访问权限是“您可以为该成员声明的最受限制的访问”,即针对类中的成员/方法/嵌套类和非嵌套类。privateinternal

在上面的文本中,“访问”是指通过类类型的对象访问,该对象在类本身的方法中将是隐式对象,或者该方法实例化当前类类型的显式对象并通过该对象访问它。两者都被视为由类本身访问,因此访问规则是相同的。这也适用于从静态方法执行的访问,或者当它是被访问的静态成员/方法时,除非访问是使用类作用域而不是 and object 执行的。静态类的成员/方法需要显式创建,否则将无法编译。thisstatic

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

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

C# 中的继承始终与 C++不同,后者可以私下或受保护地继承,然后更改所有类的访问,然后从从该类继承的类继承,以及通过对象/通过类范围访问从该类私下/受保护地继承的类的类和从私下/受保护地继承的类的类的类型范围进行访问。 等等。更改访问,使得所有访问修饰符的限制性都小于 或 和 分别。publicprivateprotectedprivateprotected

2赞 Tropin Alexey 5/13/2022 #18

我创建了另一种类型的可视化。也许这对某人来说可以是更好的理解方式

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

enter image description here

2赞 Darren 12/5/2022 #19

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

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

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

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

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

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

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

C# 11 中,还可以使用文件访问修饰符。

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

// 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();
    }
}
0赞 Ogglas 5/30/2023 #20

鉴于 Stack Exchange 中的所有站点(包括 Stack Overflow)现在都支持 Markdown 表,我在这里缺少一个答案。

汇总表:

来电者的位置 公共 受保护的内部 保护 内部 私人保护 私人
在班级内 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
派生类(同一程序集) ✔️ ✔️ ✔️ ✔️ ✔️
非派生类(同一程序集) ✔️ ✔️ ✔️
派生类(不同的程序集) ✔️ ✔️ ✔️
非派生类(不同的程序集) ✔️

源:

https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers#summary-table

https://meta.stackexchange.com/questions/356997/new-feature-table-support