“private”和“protected Internal”有什么区别?

14
我想知道privateprotected internal访问修饰符实际上有什么区别。据我所知,

对自身类成员可见: private和protected internal都是YES

对其他类对象可见: 两者都是NO

对命名空间集合之外的其他类对象可见: 两者都是NO

对子类对象在命名空间集合之外可见: 两者都是NO

如果 privateprotected internal 做相同的事情,那我们为什么需要两个修饰符,一个不就足够了吗?

1
Type.IsFamilyOrAssembly属性将为true。是OR,而不是AND。 - Hans Passant
@HansPassant,我没听懂你说什么?抱歉。 - avirk
1
好资源:http://msdn.microsoft.com/en-us/library/wxh6fsc7 - Nope
7个回答

27
  • protected internal成员对当前程序集中的任何代码另一个程序集中的派生类可见。在技术术语上,它是protectedinternal的逻辑析取(logical disjunction)
  • private成员仅对同一类中的代码可见。

protected internal实际上是仅次于public的第二个最宽松的访问修饰符。


值得注意的是,protectedinternal更宽松,因为它允许从您无法控制的代码(即其他程序集)进行访问。而internal允许所有当前程序集中的代码访问,但这些代码是您自己的,并且您能够控制它们!

换言之,protected(和protected internal)成员是您程序集的公共API的一部分(因此应该记录)。internal成员则不是。


那么什么时候应该使用protected internal而不是public呢? - avirk
@François,你最后一句话实际上不正确;protected internal是两者的并集,而不是交集。 - Will Vousden

26

一个图形化概览(简洁概括)

可见性


应该在另一个程序集中添加另一列名为“派生类”,以解释关键字“protected internal”。 - Lyubomir Velchev
@Lyubomir Velchev:确实,无论如何都应该有两个类别(同一程序集,不同程序集),在这张图中,内部的“派生类”无值应该被刻上斜线。 - Stefan Steiger

4

private 只对自己的类成员可见,而 protected internal 既可见于子类,也可见于命名空间集合中其他类。


所以 private 对于子类和命名空间集合内的其他类都是可见的。 - avirk
@avirk 不是,那是 protected internalprivate 是最严格的访问修饰符:只能被定义类使用。 - Mattias Buelens

3

私有

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

受保护的内部

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


1

我试图通过阅读不同论坛和博客提供的描述来理解.NET上下文中protected internal和internal之间的区别。我真的没有理解,然后我使用VS2015创建了2个单独的程序集。现在我可能有基本的理解了。我想与您分享,这可能对某些人有帮助。我尝试从另一个程序集中声明的字段中使用字段。我还尝试从在另一个程序集中声明的类派生。以下是来自程序集1的class1.cs的代码

namespace Z_Dll_1
{
    public class PublicBaseClassAssemblyOne
    {
        internal int _myinternal = 200;
        protected internal int _protectedinternal = 100;
        protected int _myProtected = 123;
        private int _myPrivate = 2;
        public int _myPublic = 45;
    }

    public class DerivedClassAssemblyOne : PublicBaseClassAssemblyOne
    {
        protected internal int intM = 10;
    }

    internal class MyInternalClass
    {
        public void MyMethod()
        {
            Console.WriteLine("Method one with internal class");
            PublicBaseClassAssemblyOne cl1 = new PublicBaseClassAssemblyOne();
            cl1._myinternal = 1000; //Internal type is available since it is in same assembly
            cl1._protectedinternal = 10; // protected internal is available
            cl1._myPublic = 2;  // Public OK
            //cl1.myPrivate = ?? // nor available since it is private

            DerivedClassAssemblyOne drOne = new DerivedClassAssemblyOne();
            drOne._myinternal = 30; // Internal and available from derived class
            drOne._myPublic = 1; // Public 
            drOne._protectedinternal = 2; // Able to be accessed from same assembly or derived class from other assembly
        }
    }
}

这是来自另一个程序集的代码,class2.cs: using Z_Dll_1;

namespace Z_Dll_2
{
    public class ClassAssembly2
    {
        public ClassAssembly2()
        {
            PublicBaseClassAssemblyOne classfromOtherAssembly = new PublicBaseClassAssemblyOne();
            classfromOtherAssembly._myPublic = 0; //Only public is available
        }
    }

    public class ClassDerivedFromOtherAssemblyClass : PublicBaseClassAssemblyOne
    {
        public ClassDerivedFromOtherAssemblyClass()
        {
        }
        void ClassDerivedFromOtherAssemblyClassTestMethod()
        {
            //_myinternal = 200; // can't access since it was internal to other assembly
            _protectedinternal = 100; // this can be accessed as it is  derived class from other class that has protected internal 
            _myProtected = 123; // Ordinary protected data accessed from derived class
            //_myPrivate = 2; //Private member can't be accessed from  derived class
            _myPublic = 45; // Public can be accessed anyway

            //Try to create an instance of internal class
            //MyInternalClass intClass = new MyInternalClass(); //Not accessible from this assembly
        }
    }
}

0

我认为protected internal表示只有继承且在同一程序集中的类才能看到该属性。那些从不同程序集派生该类的类,无法看到该属性。

LE: 请阅读Mattias Buelens的评论。


实际上,这是不正确的。protected internal 意味着 protected 并集 internal,因此子类和同一程序集中的其他类都可以看到它。 - Mattias Buelens
@Mattias Buelens...我的英语有点糟糕,但我想说的现在已经写下来了。 - Andrei Neagu
是的,一开始可能有点困惑,但当你看到它是两个修饰符的联合时就会明白了。 - Mattias Buelens

0
实际上,我通常只在变量上使用private关键字,以确保其他类别无法滥用它们。
然而,对于我不想让大多数其他类别使用但希望能够访问编写测试用例的方法,我经常会使用protected internal。这非常方便,因为它允许在相同的命名空间或包结构中创建测试类并访问这些受保护的内部方法,而不会不当地将它们开放给世界其他部分。
这种方法需要一种编码方法,其中编写易于“可测试”代码是优先考虑的。如果不是我的方法,我不确定我会找到很多使用protected internal的机会。

1
访问修饰符的选择不应由您对测试的需求来确定。例如,如果您有一个不需要setter的属性,则不会添加公共setter,仅允许进行测试设置。测试框架以及模拟框架能够注入私有属性等。测试会影响您在模式或可能是抽象中的选择,毕竟,如果无法模拟任何依赖项,则很难对单元进行测试。但是,测试不应影响您对访问修饰符的选择。 - Nope
+1 Francois,我也经常看到人们将私有成员设置为“internal”,再加上InternalsVisibleToAttribute来将它们暴露给单元测试程序集。 - MattDavey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接