项目A(ClassLibrary1):
有一个类:namespace ClassLibrary1
{
    public abstract class HelloBase
    {
        protected internal abstract void SayHello();
    }
}
注意 SayHello 的访问修饰符:protected internal abstract。这个原意可能有两个版本:
1、允许 ClassLibrary1 程序集访问 HelloBase.SayHello 或者让派生类(其他程序集)访问(靠谱)。
2、允许 ClassLibrary1 程序集以及所派生的程序集进行访问(显然不靠谱)。是的,我在其他程序集引用了 ClassLibrary1 并继承 HelloBase
通过 VS 2010 的快捷方式,我得到了:  public class HelloClass : ClassLibrary1.HelloBase
    {
        protected override void SayHello()
        {
            Console.WriteLine("Hello");
        }
    }
显然这是没错的。可是,为什么我在研究别人的源码时,发现已编译的程序集竟然存在:  public class HelloClass : ClassLibrary1.HelloBase
    {
        protected internal override void SayHello()
        {
            Console.WriteLine("Hello");
        }
    }那么,我该如何让它编译成功?
VS2010 的错误提示如下:错误
“ConsoleTest.HelloClass.SayHello()”: 当重写“protected”继承成员“ClassLibrary1.HelloBase.SayHello()”时,无法更改访问修饰符

解决方案 »

  1.   

    哪里来的两个版本...别想当然,MSDN早就有明确地解释...
      

  2.   

    internal 关键字是类型和类型成员的访问修饰符。只有在同一程序集的文件中,内部类型或成员才是可访问的.
      

  3.   

    你想问的我没太看懂2、允许 ClassLibrary1 程序集以及所派生的程序集进行访问(显然不靠谱)。这句话怎么不靠谱了? protected internal 本来就是可以在当前程序集中用,并且在其他程序集中的派生类也可以使用 你那个错误:因为你继承时,覆写SayHello()函数时,和父类SayHello()的签名不同
      

  4.   

    你为啥要多一个internal 修饰啊。
      

  5.   


    vrhero,这个我明白的。但是我不理解,别人是怎么实现这样的方式?
    我直接上图:
    ---------------------
    抽象类:---------------------
    派生类:
      

  6.   

    devexpress能编译通过,他是在编译检查上做修改了吧?
      

  7.   


    如果从同一个assembly内进行继承,是继续用protected internal修饰。
      

  8.   

    Reflector显示的未必就是正确的...它是通过反射得到其元数据,只是显示其具有那些修饰符...然而你在代码中不可以更改基类方法的访问修饰符,不允许显式声明...
      

  9.   

    lz可以尝试自己写一个,然后用reflector看看结果,可能就会出现这样的情况了
      

  10.   


    vrhero,可是我的源码包也是这样。其他的源码都正常,偏偏这个项目上会存在这个问题?
    然后是“故意的捣蛋”?
      

  11.   

    难道是这个起了作用?
    /addmodule(导入元数据)
      

  12.   

    "编译器错误 CS0507"说的是C#编译器。其他编译器可能不采用该规则。
    比如下面代码将编译出internal protected(注意famorassem修饰)://
    // hello.il
    // 编译命令:ilasm /dll hello.il
    // 需要当前目录有程序集ClassLibrary1.dll
    //
    .assembly extern ClassLibrary1{}
    .assembly extern mscorlib
    {
      .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
      .ver 2:0:0:0
    }.assembly ClassLibrary2{}
    .module ClassLibrary2.dll
    .subsystem 0x0003       // WINDOWS_CUI
    .corflags 0x00000001    //  ILONLY.class public auto ansi beforefieldinit Hello
           extends [ClassLibrary1]ClassLibrary1.HelloBase
    {
      .method famorassem hidebysig virtual instance void 
              SayHello() cil managed
      {
        ret
      }  .method public hidebysig specialname rtspecialname 
              instance void  .ctor() cil managed
      {
        ldarg.0
        call       instance void [ClassLibrary1]ClassLibrary1.HelloBase::.ctor()
        ret
      }
    }
      

  13.   

    显然,只有将所有的  protected internal 全部改成 public 才是解决之道啊……
      

  14.   


    protected不带internal的区别就是从当前的程序集非继承不能调用。
    如果你不只是好奇,还想要得到internal的效果,那么可以添加一个转发函数,来达到同样的目的:public class Hello : ClassLibrary1.HelloBase
    {
        protected override void SayHello()
        {
        }    internal void SayHelloInternal()     //<---
        {
            this.SayHello();
        }
    }
      

  15.   


    gomoku ,十分感谢您的积极回复。您的精神很令我感动。
    我最终还是决定将所有的 protected internal 转换为 public。这个改动量比较小
      

  16.   

    灰太狼你好,看到你7楼给的图,知道你要问什么了。
    你只注意了那个程序集,但是忽略了命名空间,仔细看下那两个类虽然不是同一个程序集,但是命名空间都一样,都是“DevExpress.XtraRichEdit.Layout.Export”命名空间哦,哈哈!
      

  17.   

    楼主给的图,从反编译的情况来看,确实是这么回事的。但从理论上说是应该编译不过。很可惜手头没有10.2的源码。DecExpress确实很喜欢用protected internal;我看了手头7.3的源码,全工程并没有出现这种有违语法的现象。(注:7.3没有RichEdit,我只参参考RichText)。经过代码发现:DEV中有很多“protected internal new”的实现。另一种可能,会不会Dev把相关代码进行了混淆(我想应该不会,如果这样还不如加密)。
      

  18.   

    An interesting assembly-level attribute introduced by .NET 2.0 is the InternalsVisibleTo attribute, defined in the System.Runtime.CompilerServices namespace. This attribute allows you to expose internal types and methods to clients from another specified assembly. This is also known as declaring a friend assembly. For example, suppose the server assembly MyClassLibrary.dll defines the internal class MyInternalClass as:    internal class MyInternalClass
        {
           public void MyPublicMethod(  )
           {...}
           internal void MyInternalMethod(  )
           {...}
        }If you add this line to the AssemblyInfo.cs file of MyClassLibrary.dll:    [assembly: InternalsVisibleTo("MyClient")]any client in the assemblies MyClient.dll and MyClient.exe will be able to use MyInternalClass and call its public or internal members. In addition, any subclass in the MyClient assembly will be able to access members ed as protected internal.