4

此属性在没有访问修饰符的类型中(因此internal访问):

class SomeType {
    private int length;
    internal int Length {
        get { return length; }
        set length = value; }
    }
}

允许 SomeType 程序集中的所有类型使用getset访问器。问题:如何将访问限制为set仅从SomeType派生的类型(确实是 SomeType )?

internal int Length {
    get { return length; }
    protected set length = value; }
}

被编译器拒绝,因为protected据说限制性低于internal(假设:与protected交集internal,但不完全包含internal--> 派生类型可以存在于 的范围之外internal)。

可以由程序集中的任何类型访问并且仅由程序集中的派生类型设置的代码是什么?

编辑:查看答案后,我想我需要添加该属性的另一个特征,因为它可能会在解决方案中有所不同:该属性的类型实际上是SomeType. 编辑后的代码是:

class SomeType {
    private SomeType length;
    internal SomeType Length {
        get { return length; }
        set length = value; }
    }
}

如果声明了属性public,则编译器会发出错误(属性类型 SomeType 无法访问属性 Length)。

4

3 回答 3

5

(编辑:我刚刚检查过,即使属性的类型与声明类型相同,这也有效。但是,当您尝试在公共类型中声明该类型的属性时,它不起作用的属性是内部类型。)

你不能在 C# 中完全做到这一点(严格来说),但你可以做一些非常相似的事情:

protected internal int Length { get; protected set; }

(这只是为了简单而使用自动实现的属性;同样的技术也适用于“正常”属性。)

这将使同一程序集派生类型中的任何类型都可以访问“getter”;“setter”只能被派生类型访问。由于您的类无论如何都是内部的,因此无论如何这几乎是等效的 - 理论上,getter 可以被程序集外部的类型访问,但是由于该类是内部的,因此无论如何都不应该从您的类型派生任何来自不同程序集的内容。

问题是属性要求一个访问级别是另一个访问级别的“子集”。internal并且protected不要那样工作 - 一种类型可以在同一个程序集中,但不是从相关类型派生的;可以从它派生另一种类型,但在不同的程序集中。它们基本上是正交的。

上述解决方案之所以有效,是因为这protected internal意味着它可以被同一程序集中从该类型派生的任何类型访问。很明显,每一个protectedinternal单独都是这个的一个子集。

如果 C# 具有与 CLR“系列程序集”访问级别等效的属性,则您能够为设置器创建一个进一步限制的属性。(相当于“家庭集会”。)不幸的是,它没有:(internalprotected internal

如果您真的想要最初声明的目标(例如,如果您以后有一个想要应用相同限制的公共类),则必须将其中至少一个设为单独的方法,例如

private int length;
internal int Length { get { return length; } }

protected void SetLength(int value)
{
    this.length = value;
}
于 2010-01-17T14:24:07.703 回答
3

由于类本身仅在声明程序集中可见(由于隐式internal访问修饰符),因此只需在属性public和 setter上设置 getter protected

class SomeType {
    private int length;

    public int Length {
        get { return length; }
        protected set { length = value; }
    }
}

由于类本身不可见,因此无法在程序集之外访问getter 。


题外话:如果你有一个最近的 C# 编译器,你可能想要使用自动属性来代替:

class SomeType {
    public int Length { get; protected set; }
}

这只是一种语言/编译器技巧,因此您不必针对版本 3.X 框架进行编译即可使用它。

于 2010-01-17T14:31:12.133 回答
-1

你不能把它转过来(还没有测试过):

protected int Length
{
    internal get { return length; }
    set { length = value; }
}
于 2010-01-17T14:21:56.253 回答