ChatGPT解决这个技术问题 Extra ChatGPT

在 C# 中,public、private、protected 和没有访问修饰符有什么区别?

我在大学期间一直在使用 public,想知道 publicprivateprotected 之间的区别吗?

另外,static 做什么而不是什么都没有?


C
Community

访问修饰符

docs.microsoft.com

public 类型或成员可以由同一程序集或引用它的另一个程序集中的任何其他代码访问。 private 类型或成员只能被同一类或结构中的代码访问。 protected 类型或成员只能由同一类或结构中的代码或派生类中的代码访问。 private protected(在 C# 7.2 中添加)该类型或成员只能由同一类或结构中的代码或同一程序集的派生类中的代码访问,但不能从另一个程序集访问。 internal 类型或成员可以由同一程序集中的任何代码访问,但不能从另一个程序集中访问。 protected internal 同一程序集中的任何代码或另一个程序集中的任何派生类都可以访问该类型或成员。

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

静态修饰符

类上的 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 和有什么不一样?对我来说,听起来两者都是一样的..
S
Stefan Steiger

图形概览(简而言之)

https://i.stack.imgur.com/ExkwO.png

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

因此需要扩展概述:

https://i.stack.imgur.com/TNtq3.png

另请参阅 C#-dotnet-docs on the subject

由于 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 中,关键字有时是不同的,所以这里有一个备忘单:

https://i.stack.imgur.com/o6BZf.png


@ᴀʀᴜn BᴇrtiL:你确定吗?不同程序集中的派生类?
我们可以在同一个程序集中派生类,我们不能不同。我以为你的意思是在同一个程序集中......
@ᴀʀᴜn BᴇrtiL:嗯,对,这实际上应该是孵化的。
我认为图表中有错误。如果 internal 用于类,则该类可以由同一程序集中的另一个类派生。此外,如果在属性上使用 internal 修饰符,则也可以在同一程序集中的派生类中访问此属性。也许该图是正确的,因为“包含程序集”下有一个“是”,但它可能会被误解,因为“派生类”下有一个“否”。
J
JosephStyons

Public - 如果你可以看到类,那么你可以看到方法

Private - 如果您是班级的一员,那么您可以看到该方法,否则不能。

受保护 - 与私有相同,而且所有后代也可以看到该方法。

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

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


你不能在非静态类中有静态方法吗?
是的,但我说的是静态类。我添加了一个单独的条目来描述静态方法。谢谢你的收获。
在谈论 C# 时,“对象”在这里可能不是一个好词,因为所有类的基本类型都是 System.Object。 “实例”会是一个更好的词,或者“对象”(小写“O”)。
@lesderid 'object' 是 'System.Object' 的别名,使用它也可能会造成混淆。 '实例'会更好,我想:)
相同的规则适用于结构。
P
Pang

重新发布来自 this answer 的精彩图表。

以下是维恩图中的所有访问修饰符,从更多限制到更混杂:私有:私有受保护:-在 C# 7.2 中添加内部:受保护:受保护内部:公共:


u
user1810087

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

https://raw.githubusercontent.com/gist/michail-peterlis/67ab9f81f16cd2fb074d8ea9c8008653/raw/1b41929acf1cab64b4cb386966659e079a9edef5/access_modifier.svg

外 内

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

私有保护:私有外部(同一个程序集)受保护内部(同一个程序集)

受保护的内部:受保护的外部(相同的组件)内部的内部(相同的组件)


N
Narottam Goyal

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,它将是:相同的类 = Yes,相同的程序集,派生类 = Yes,相同的程序集,任何类 = NO,不同的程序集,派生类 = NO,不同的程序集,任何类 = NO。另一个建议是不要切换 protected internal 的词序,因为这会破坏@user1810087 的答案
l
leppie

关于一无所有的问题

默认情况下,命名空间类型是内部的

默认情况下,任何类型成员,包括嵌套类型都是私有的


J
Johnny Bones

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

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


Φ
ΦXocę 웃 Пepeúpa ツ

唔。

请参见此处:Access Modifiers

简而言之:

Public 为其他类型/类提供方法或类型的完全可见性。

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

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

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

public class MyClass
{
    string s = "";
}

实际上与以下内容相同:

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

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


g
gbianchi

嗯……

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

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


r
radu florescu

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

“从上表中我们可以看到私有和受保护之间的区别......我认为两者都是相同的......所以这两个单独的命令需要什么”

查看 MSDN 链接了解更多信息


P
Pang

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

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


L
Lewis Kelsey

public 意味着它可以被任何程序集中的任何类访问,包括类本身。

受保护的内部意味着它可以被类本身访问(在类定义中),并且它可以被当前程序集中的任何类访问,但在程序集之外它只能被继承该类的类访问,或者由类本身(如果它是一个部分类) - 基本上它意味着在程序集中内部并在程序集外部受到保护。

protected 意味着它只能由类本身访问,或者由继承它的类访问,并且该类可以在任何程序集中

internal 意味着它可以被类本身或程序集中的任何类访问,但在程序集之外根本不能访问,除非类本身(即它是一个部分类)

私有保护意味着它只能被类本身访问,或者它可以被继承它的类访问,并且只有当该类在当前程序集中时。在程序集之外,它只能由类本身访问(即它是一个部分类)——基本上结合了内部和保护,或者另一种说法是它在程序集之外是私有的,在程序集内部是保护的。

private 表示只能由类本身访问

无访问修饰符:C# 中所有内容的默认访问权限是“您可以为该成员声明的最受限制的访问权限”。它对于类中的成员/方法/嵌套类是私有的,对于非嵌套类是内部的。

在上面的文本中,“已访问”表示通过类类型的对象进行访问,该对象在类本身的方法中将是隐式 this 对象,或者该方法可能实例化当前类类型的显式对象并访问它通过那个物体。两者都被认为是由类本身访问的,因此访问规则是相同的。这也适用于从静态方法执行的访问,或者当它是被访问的静态成员/方法时,除了使用类范围而不是对象执行访问。静态类的成员/方法需要显式创建 static 否则将无法编译。

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

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

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


j
jpfollenius

这些访问修饰符指定您的成员可见的位置。您可能应该阅读此内容。以 IainMH 提供的链接为起点。

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


C
Chazt3n

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


P
Pang

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

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

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

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

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

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

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

私有受保护:使用此可访问性声明的成员可以在从包含程序集中的此包含类型派生的类型中可见。对于不是从包含类型派生的任何类型或在包含程序集之外的任何类型,它都是不可见的。即,访问仅限于包含程序集中的派生类型。

Source including a sample code of the new private protected access modifier


T
Tropin Alexey

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

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

https://i.stack.imgur.com/V2fpE.png


s
snr

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

https://i.stack.imgur.com/cXw9o.png