我正在将一些Java代码移植到C#,我遇到了这个用于复制对象的习惯用法:
class Base
{
int x;
public Base(int x) { this.x = x; }
protected Base(Base other) { x = other.x; }
}
class Derived : Base
{
Base foo;
public Derived(Derived other)
: base(other)
{
foo = new Base(other.foo); // Error CS1540
}
}
错误CS1540:
无法通过“Base”类型的限定符访问受保护的成员“Base.Base(Base)”;限定符必须是'Derived'类型(或从中派生出来)
我理解此错误的目的:它阻止访问兄弟类型的受保护成员。但Base.Base(Base)显然不会在兄弟类型上调用!这根本没有包含在规范中,或者我错过了为什么这不安全的原因?
编辑:Gah,成语是new Base(other.foo)
而不是new Base(other)
答案 0 :(得分:4)
语言规范的第3.5.2节和第3.5.3节说明了这一点,为方便起见,我将发布3.5.2(它更短!)并让你自己找到3.5.3。
直观地说,当一个类型或 访问成员M,如下 评估步骤以确保 允许访问:
- 首先,如果在一个类型中声明了M(而不是编译单元) 或命名空间),编译时错误 如果无法访问该类型,则会发生。
- 然后,如果M是公开的,则允许访问。
- 否则,如果M受内部保护,则允许访问 它发生在程序中 M被声明,或者如果它发生在 从类派生的类 M被宣布并发生 通过派生类类型 (§3.5.3)。
- 否则,如果M受保护,则允许访问(如果发生) 在M所在的类中 声明,或者如果它发生在 从类中派生的类 M被宣布并通过 派生类类型(§3.5.3)。
- 否则,如果M是内部的,则允许访问,如果它发生 在M所在的计划中 声明。
- 否则,如果M是私有的,则允许访问,如果它发生 在M的类型内 声明。
- 否则,类型或成员不可访问,并且编译时错误 发生。
基本上,对基础的受保护成员的访问必须通过派生的实例。正如您所说,兄弟姐妹不能访问彼此的受保护成员,但语言规范也禁止儿童访问基地的受保护成员,除非通过儿童提及。
答案 1 :(得分:4)
我可以执行此操作,然后您可以始终轻松调用允许您从中派生的任何类的protected
个成员,即使派生的也是如此不使用类。这完全颠覆了protected
机制的安全性。
例如,假设我们从Base
推导出Derived
,如上所述。如果规则不是这样,您可以将这样的方法添加到Derived
:
public static void CallProtectedMethod(Base baseInstance)
{
baseInstance.ProtectedMethod();
}
现在任何人都可以像这样调用它:
Derived.CallProtectedMethod(baseInstance);
直接接近失败:
baseInstance.ProtectedMethod();
在这种情况下,baseInstance
可能确实属于Base
类型,与Derived
无关。为了防止这种情况并确保protected
方法保持protected
,除非实例确实属于Derived
类型,否则通过其他实例调用这些方法是非法的。
同样适用于protected
构造函数:
public static Base CreateProtectedBase()
{
return new Base();
}
现在任何人都可以像这样调用它:
var baseInstance = Derived.CreateProtectedBase();
直接接近失败:
var baseInstance = new Base();
答案 2 :(得分:3)
无法访问,您可以查看此帖子了解详情:Many Questions: Protected Constructors
答案 3 :(得分:1)
如果在派生中创建新的base对象,则无法通过该对象访问受保护的成员。 试试这段代码
class Base
{
protected int x;
}
class Derived : Base
{
Base foo;
void testMethod()
{
base.x = 5;
foo.X = 5;// this throws an error
}
}
更改构造函数的访问说明符以使其工作或代替创建基类对象(Base)使用base.X