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


728

我所有的大学四年我一直在使用public,并想知道的区别publicprivateprotected

还有什么static而不是什么都不做呢?

Answers:


1007

访问修饰符

来自docs.microsoft.com

public

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

private

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

protected

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

private protected (在C#7.2中添加)

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

internal

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

protected internal

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

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

static 修饰符

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

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

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

static class Foo()
{
    static Foo()
    {
        Bar = "fubar";
    }

    public static string Bar { get; set; }
}

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

MyStaticClass.ServiceMethod(...);

17
您可以在非静态类中使用静态方法,对吗?
John Bubriski

14
是的,它们的行为与我的示例相同。
mbillard

7
在这种情况下,术语“装配”是什么意思?
乔纳森·格里森

1
@gotoVoid您在Google上搜索的任何内容都不正确。根据MSDN,受保护的内部含义是:“可以在声明了该类型或成员的程序集中的任何代码中,或从另一个程序集中的派生类中访问该类型或成员”。
凯文(Kevin)

2
受保护和私有受保护之间有什么区别?对我来说,听起来都一样..
goofyui

161

图形概述(概述)

能见度

由于静态类是密封的,因此不能继承它们(从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

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

VB与CS等效


1
@ᴀʀᴜnBᴇrtiL:确定吗?不同程序集中的派生类?
Stefan Steiger,2015年

我们可以在同一程序集中派生类,不同的我们不能。我认为您的意思像在同一程序集中...
Arun Bertil

1
@ᴀʀᴜnBᴇrtiL:嗯,对,这实际上应该是阴影线。
Stefan Steiger 2015年

1
我认为图表中有错误。如果将internal用于一个类,则该类可以由同一程序集中的另一个类派生。同样,如果将内部修饰符用于属性,则也可以在同一程序集中的派生类中访问此属性。该图可能是正确的,因为在“包含程序集”下有一个“是”,但是由于在“派生类”下有一个“否”,因此它可能会被误解。
啊。

160

公共 -如果您可以看到该类,则可以看到该方法

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

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

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

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


1
但是,在非静态类中不能有静态方法吗?
约翰·布布里斯基

1
是的,但是我在谈论静态类。我添加了一个单独的条目来描述静态方法。谢谢你的收获。
JosephStyons

2
在谈论C#时,“ Object”可能不是一个好术语,因为所有类的基本类型都是System.Object。“实例”将是一个更好的词,或者是“对象”(小写的“ O”)。
lesderid 2012年

@lesderid'object'是'System.Object'的别名,使用它也可能会造成混淆。我想'instance'会更好:)
dpp

相同的规则适用于结构。
gsharp 2014年


24

在此处输入图片说明

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
我看不出这个答案比过去五年来的其他答案多了什么。
约翰·桑德斯

4
这只是一个简单的解释。由于其他答案有些令人困惑,而一半答案是:)
Narottam Goyal,2015年

4
@John Saunders:它通过将同一类中的派生类与不同程序集中的类之间的可见性分开来进行区分。另外,他通过显示示例代码提供了如何获取该信息。因此,它实际上增加了其他答案。我的回答很可能触发了他的清算。
Stefan Steiger

2
“不同程序集中的派生类”-这为另一个答案中已经给出的图表增加了价值。这种区别特别有帮助,特别是在“受保护的内部”情况下
Nirman 18'Jan

我发现此图表是我最容易理解的图表。为了保持当前状态(使用C#7.2),要添加Private Protected,将是:相同的类= Yes,相同的程序集,派生的类= Yes,相同的程序集,任何类= NO,不同的程序集,派生的类= NO,不同的程序集,任何class = NO。还有一个建议是不要更改单词顺序protected internal,因为这会打破@ user1810087的回答引起的肺炎
Instellar Explorer

22

关于什么都没有的问题

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

15

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

交互式访问修饰符svg

外在内

如果您难以记住两个单词的访问修饰符,请记住outside-inside

  • 私有受保护私有 外部(同一程序集)受保护 内部(同一程序集)
  • 受保护的内部受保护的 外部(相同的组件)内部的 内部(相同的组件)

11

参见此处: 访问修饰符

简而言之:

Public使方法或类型对其他类型/类具有完全的可见性。

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

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

“无”是VB.NET的等效于null。尽管如果您指的是“ nothing”(无访问修饰符),那么它取决于(尽管很粗略的经验法则(在C#中确实如此)是,如果您未明确指定访问修饰符,则方法/变量声明通常受到限制。即

public class MyClass
{
    string s = "";
}

实际上与以下内容相同:

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

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


8

公共 -任何地方的任何人都可以访问。
私有 -只能从属于它的类中的with进行访问。
受保护 -只能从类中的with或从该类继承的任何对象中访问。

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


4

嗯...

静态意味着您无需类的实例即可访问该函数。

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


4

私有状态指示变量只能由相同类的对象访问。受保护的状态将访问权限扩展到了该类的后代。

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

检查MSDN链接以获取更多信息


3

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

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


3

仔细观察您对课程的可访问性。默认情况下,每个人都可以访问公共和受保护的类和方法。

当在Visual Studio中创建新类时,Microsoft也不十分明确地显示访问修饰符(公共,受保护等)。因此,请小心并考虑您对类的可访问性,因为它是实现内部的大门。


2

我认为这与良好的OOP设计有关。如果您是图书馆的开发人员,则想隐藏图书馆的内部作品。这样,您可以稍后修改库的内部工作方式。因此,您将成员和助手方法设置为私有,而只有接口方法是公开的。应该覆盖的方法应受到保护。


1

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

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

protected:具有此可访问性的成员声明可以在包含程序集的包含类型派生的类型以及包含程序集之外的包含类型派生的类型中看到。也就是说,访问仅限于包含类型的派生类型。

internal:具有此可访问性声明的成员在包含该成员的程序集中可以看到,对于包含该程序集之外的任何程序集都不可见。也就是说,访问仅限于仅包含程序集。

内部受保护的:声明具有此可访问性的成员在包含程序集内部或外部的包含类型派生的类型内都是可见的,对于包含程序集内的任何类型也可见。也就是说,访问仅限于包含程序集或派生类型。

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

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

private protected:具有此可访问性的成员声明可以在包含程序集的此包含类型派生的类型中看到。对于不是从包含类型派生的任何类型,或者在包含程序集外部的任何类型,它都是不可见的。也就是说,访问仅限于包含程序集内的派生类型。

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


0

C#的所有访问修饰符说明

在此处输入图片说明

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.