这是我缩短的抽象类:
abstract class Report {
protected internal abstract string[] Headers { get; protected set; }
}
这是派生类:
class OnlineStatusReport : Report {
static string[] headers = new string[] {
"Time",
"Message"
}
protected internal override string[] Headers {
get { return headers; }
protected set { headers = value; }
}
internal OnlineStatusReport() {
Headers = headers;
}
}
我的想法是,我希望能够从程序集中的任何位置调用Report.Headers
,但只允许它由派生类设置。我试着让Headers
只是内部的,但受保护不算比内部更严格。有没有办法使Headers内部及其set访问器受到内部保护?
我觉得我严重滥用访问修饰符,所以任何设计帮助都会非常感激。
答案 0 :(得分:31)
在C#中不可能。
为了完整起见,IL(家庭和程序集访问修饰符)支持此功能。
答案 1 :(得分:16)
将吸气剂公开有什么问题?如果您将该属性声明为
public string[] Headers { get; protected set; }
它符合您想要的所有条件:程序集的所有成员都可以获取属性,并且只有派生类可以设置它。当然,集会外的课程也可以获得房产。所以?
如果您确实需要在程序集中公开属性但不公开,则另一种方法是创建不同的属性:
protected string[] Headers { get; set; }
internal string[] I_Headers { get { return Headers; } }
当然,使用I_
前缀装饰名称很难看。但这是一种奇怪的设计。在内部属性上进行某种名称修改是一种提醒自己(或其他开发人员)他们正在使用的属性是非正统的方式。此外,如果您稍后决定这样的混合可访问性不是您问题的正确解决方案,那么您将知道要修复哪些属性。
答案 2 :(得分:6)
我会将访问修饰符保持为受保护并具有内部帮助方法。
protected override string[] Headers {
get { return headers; } // Note that get is protected
set { headers = value; }
}
internal SetHeadersInternal(string[] newHeaders)
{
headers = newHeaders;
}
但不知何故,这闻起来应该以某种方式重构。内部总是我谨慎使用的东西,因为它可能导致一个非常混乱的架构,其中一切都以某种方式使用集合中的其他东西,但当然总是例外。
答案 3 :(得分:6)
您可以使用内部显式实现的接口:
internal interface IReport
{
string[] Headers { get; }
}
abstract class Report : IReport
{
protected abstract string[] Headers { get; protected set; }
string[] IReport.Headers
{
get { return Headers; }
}
}
class OnlineStatusReport : Report
{
static string[] headers = new string[] { "Time", "Message" };
protected internal override string[] Headers
{
get { return headers; }
protected set { headers = value; }
}
internal OnlineStatusReport()
{
Headers = headers;
}
}
现在,您可以在定义了IReport的程序集中获得内部访问权限,这应该是您想要的。
显式实现接口并不是一个众所周知的策略,但它解决了很多问题。
答案 4 :(得分:3)
CLR支持受保护的AND内部概念(称为系列和程序集可访问性),C#应该实现/公开这个概念。 C#应该允许以下内容:
internal string[] Header { get; protected set; }
这样做应该INTERSECT / AND属性设置器的两个可见性修饰符,并允许您从同一个程序集中的任何位置读取Headers,但只能从同一程序集中的派生类设置它。
答案 5 :(得分:2)
人们普遍认为,你不能让一些成员受到保护和内部保护。
而且你不能在一条线上这样做,正如许多人,包括我自己所希望的那样,但有一些聪明才能100%做到。
//Code below is 100% tested
/* FROM ProtectedAndInternal.dll */
namespace ProtectedAndInternal
{
public class MyServiceImplementationBase
{
protected static class RelevantStrings
{
internal static string AppName = "Kickin' Code";
internal static string AppAuthor = "Scott Youngblut";
}
}
public class MyServiceImplementation : MyServiceImplementationBase
{
public void PrintProperties()
{
// WORKS PERFECTLY BECAUSE SAME ASSEMBLY!
Console.WriteLine(RelevantStrings.AppAuthor);
}
}
public class NotMyServiceImplementation
{
public void PrintProperties()
{
// FAILS - NOT THE CORRECT INHERITANCE CHAIN
// Error CS0122: 'ProtectedAndInternal.MyServiceImplementationBase.Relevant' is inaccessible due to its protection level
// Console.WriteLine(MyServiceImplementationBase.RelevantStrings.AppAuthor);
}
}
}
/* From AlternateAssemblyService.dll which references ProtectedAndInternal.dll */
namespace AlternateAssemblyService
{
public class MyServiceImplementation : MyServiceImplementationBase
{
public void PrintProperties()
{
// FAILS - NOT THE CORRECT ASSEMBLY
// Error CS0117: 'ProtectedAndInternal.MyServiceImplementationBase.RelevantStrings' does not contain a definition for 'AppAuthor'
// Console.WriteLine(RelevantStrings.AppAuthor);
}
}
}
答案 6 :(得分:2)
从C#7.2开始,有private protected
(link)。它不允许从场上读取(因此不能完全符合OP的意图),但值得掠夺。
答案 7 :(得分:0)
不是完美的解决方案,而是可行的解决方案,请明确实现:
internal bool _allowSetHeader = false;
protected void SetHeader(string[] newValue)
{
if (_allowSetHeader)
{
headers = newValue;
}
}
SetHeader只能由派生类访问,除非_allowSetHeader设置为true(只能由内部类完成),否则它将什么都不做。