如何让 protected internal 跨程序集!

颤菊大师 2011-01-19 03:08:54
项目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()”时,无法更改访问修饰符
...全文
444 26 打赏 收藏 转发到动态 举报
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
eisai2000 2011-06-09
  • 打赏
  • 举报
回复
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 marked as protected internal.
颤菊大师 2011-01-24
  • 打赏
  • 举报
回复
有一个程序集特性……可以实现这样的效果。
也就是C#版的“友元”!结贴!
showjancn 2011-01-20
  • 打赏
  • 举报
回复
楼主给的图,从反编译的情况来看,确实是这么回事的。

但从理论上说是应该编译不过。很可惜手头没有10.2的源码。

DecExpress确实很喜欢用protected internal;我看了手头7.3的源码,全工程并没有出现这种有违语法的现象。(注:7.3没有RichEdit,我只参参考RichText)。

经过代码发现:DEV中有很多“protected internal new”的实现。

另一种可能,会不会Dev把相关代码进行了混淆(我想应该不会,如果这样还不如加密)。
qldsrx 2011-01-19
  • 打赏
  • 举报
回复
灰太狼你好,看到你7楼给的图,知道你要问什么了。
你只注意了那个程序集,但是忽略了命名空间,仔细看下那两个类虽然不是同一个程序集,但是命名空间都一样,都是“DevExpress.XtraRichEdit.Layout.Export”命名空间哦,哈哈!
颤菊大师 2011-01-19
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 gomoku 的回复:]

引用 18 楼 mrlen 的回复:


protected不带internal的区别就是从当前的程序集非继承不能调用。
如果你不只是好奇,还想要得到internal的效果,那么可以添加一个转发函数,来达到同样的目的:
C# code

public class Hello : ClassLibrary1.HelloBase
{
protected override void……
[/Quote]

gomoku ,十分感谢您的积极回复。您的精神很令我感动。
我最终还是决定将所有的 protected internal 转换为 public。这个改动量比较小
gomoku 2011-01-19
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 mrlen 的回复:]
[/Quote]

protected不带internal的区别就是从当前的程序集非继承不能调用。
如果你不只是好奇,还想要得到internal的效果,那么可以添加一个转发函数,来达到同样的目的:

public class Hello : ClassLibrary1.HelloBase
{
protected override void SayHello()
{
}

internal void SayHelloInternal() //<---
{
this.SayHello();
}
}

颤菊大师 2011-01-19
  • 打赏
  • 举报
回复
显然,只有将所有的 protected internal 全部改成 public 才是解决之道啊……
颤菊大师 2011-01-19
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 gomoku 的回复:]

"编译器错误 CS0507"说的是C#编译器。其他编译器可能不采用该规则。
比如下面代码将编译出internal protected(注意famorassem修饰):
Assembly code

//
// hello.il
// 编译命令:ilasm /dll hello.il
// 需要当前目录有程序集ClassLibrary1.dll
//
.assembly extern Cla……
[/Quote]

无法让 VS2010 忽略这个错误?或“跳过”、“绕过”检查?
gomoku 2011-01-19
  • 打赏
  • 举报
回复
"编译器错误 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
}
}
颤菊大师 2011-01-19
  • 打赏
  • 举报
回复
难道是这个起了作用?


/addmodule(导入元数据)
颤菊大师 2011-01-19
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 vrhero 的回复:]

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

vrhero,可是我的源码包也是这样。其他的源码都正常,偏偏这个项目上会存在这个问题?
然后是“故意的捣蛋”?
macooidle 2011-01-19
  • 打赏
  • 举报
回复
lz可以尝试自己写一个,然后用reflector看看结果,可能就会出现这样的情况了
vrhero 2011-01-19
  • 打赏
  • 举报
回复
Reflector显示的未必就是正确的...它是通过反射得到其元数据,只是显示其具有那些修饰符...然而你在代码中不可以更改基类方法的访问修饰符,不允许显式声明...
gomoku 2011-01-19
  • 打赏
  • 举报
回复
[Quote=引用楼主 mrlen 的回复:]
...
可是,为什么我在研究别人的源码时,发现已编译的程序集竟然存在:
public class HelloClass : ClassLibrary1.HelloBase
{
protected internal override void SayHello()
{
Console.WriteLine("Hello");
}
}
...
[/Quote]

如果从同一个assembly内进行继承,是继续用protected internal修饰。
颤菊大师 2011-01-19
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 zhgroup 的回复:]

devexpress能编译通过,他是在编译检查上做修改了吧?
[/Quote]
我猜测也是这样。这样很纠结啊!不知道有没有办法绕过编译检查!
zhgroup 2011-01-19
  • 打赏
  • 举报
回复
devexpress能编译通过,他是在编译检查上做修改了吧?
颤菊大师 2011-01-19
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 jjx0224 的回复:]

你想问的我没太看懂

2、允许 ClassLibrary1 程序集以及所派生的程序集进行访问(显然不靠谱)。

这句话怎么不靠谱了?

protected internal 本来就是可以在当前程序集中用,并且在其他程序集中的派生类也可以使用

你那个错误:因为你继承时,覆写SayHello()函数时,和父类SayHello()的签名不同
[/Quote]

我指的不靠谱是,仅限于“其他程序集的派生类访问”,而非“其他程序集访问”。
颤菊大师 2011-01-19
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 qldsrx 的回复:]

你为啥要多一个internal 修饰啊。
[/Quote]

这并不是“我要”,而是不理解“为什么这样能够编译成功”?
颤菊大师 2011-01-19
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 vrhero 的回复:]

哪里来的两个版本...别想当然,MSDN早就有明确地解释...
引用 MSDN:protected internal 访问仅限于从包含类派生的当前程序集或类型。
[/Quote]

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

---------------------
派生类:


qldsrx 2011-01-19
  • 打赏
  • 举报
回复
你为啥要多一个internal 修饰啊。
加载更多回复(5)

110,533

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧