如何在C#中使属性受到保护并处于内部状态?
这是我缩短的抽象类:如何在C#中使属性受到保护并处于内部状态?,c#,access-modifiers,C#,Access Modifiers,这是我缩短的抽象类: abstract class Report { protected internal abstract string[] Headers { get; protected set; } } 下面是一个派生类: class OnlineStatusReport : Report { static string[] headers = new string[] { "Time", "Message" } p
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
,但只允许由派生类设置它。我尝试将标题设置为内部标题,但受保护的标题并不比内部标题更具限制性。有没有一种方法可以使头成为内部的,并且它的集合访问器是受保护的和内部的
我觉得我严重滥用了访问修饰符,因此非常感谢任何设计帮助。这在C#中是不可能的
为了完整起见,IL(族和程序集访问修饰符)中支持这一点。我会将访问修饰符保持为受保护状态,并使用一个内部助手方法
protected override string[] Headers {
get { return headers; } // Note that get is protected
set { headers = value; }
}
internal SetHeadersInternal(string[] newHeaders)
{
headers = newHeaders;
}
但不知何故,这闻起来似乎应该以某种方式进行重构。内部总是我会少用的东西,因为它会导致一个非常混乱的体系结构,在这个体系结构中,所有的东西都在以某种方式使用程序集中的其他所有东西,但当然总会有例外。公开getter有什么错?如果您将财产声明为
public string[] Headers { get; protected set; }
它满足您想要的所有条件:程序集的所有成员都可以获得该属性,并且只有派生类可以设置该属性。当然,程序集之外的类也可以获取该属性。那么
如果确实需要在程序集中公开属性,但不公开,另一种方法是创建不同的属性:
protected string[] Headers { get; set; }
internal string[] I_Headers { get { return Headers; } }
当然,用I.
前缀来修饰名字很难看。但这是一种奇怪的设计。对内部属性进行某种名称篡改是一种提醒自己(或其他开发人员)他们使用的属性是非正统的方式。此外,如果您后来认为这样的混合可访问性并不是解决问题的正确方法,那么您将知道要修复哪些属性。人们普遍认为,您无法使某些成员既受保护又处于内部
诚然,你不能像很多人,包括我自己,所希望的那样,在一行中做到这一点,但有了一些聪明,它是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);
}
}
}
您可以使用内部显式实现的接口:
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的程序集中获得内部访问权限,这正是您想要的
明确实现接口不是一个众所周知的策略,但它解决了很多问题。CLR支持受保护和内部(称为族和程序集可访问性)的概念,C#应该实现/公开这个概念。C#可能应允许以下情况:
internal string[] Header { get; protected set; }
这样做应该与属性setter的两个可见性修饰符相交/和,并允许您从同一程序集中的任何位置读取标题,但只能从同一程序集中的派生类进行设置。因为C#7.2中存在构造私有保护
()。它不允许从现场读取数据(因此不完全符合OP的意图),但值得获取战利品。不完美,但却是可行的解决方案,请明确实施:
internal bool _allowSetHeader = false;
protected void SetHeader(string[] newValue)
{
if (_allowSetHeader)
{
headers = newValue;
}
}
SetHeader只能由派生类访问,除非将“allowSetHeader”设置为true,否则它将不起任何作用,而这只能由内部类完成…@Noldorin:protected internal是protected或internal。@Mehrdad:是的,我知道。重点是什么?@Noldorin:重点是,显然,编译精细并不是OP想要的……”想法是,我希望能够从程序集中的任何地方调用Report.header,但只允许它由派生类设置。“-发布的代码不是这样吗?说到底,也许我误解了。@Noldorin:他的意思是(据我所知),他希望只有在两个条件都满足时才能访问该成员:该类是派生类,并且位于同一程序集中。也就是说,同一程序集中的非派生类无法访问它。protected internal无法实现这一点。CLR支持protected和internal(称为族和程序集可访问性)的概念,我在上面的回答建议C#应该实现/公开这一概念,并对建议的语法进行解释。注意,我在属性上放置了内部修饰符,在setter上放置了受保护修饰符(在setter上放置“受保护的内部”时不同)。谢谢你的评论,我编辑了我的答案来强调这个观点,避免将来的混淆。它应该在某种程度上支持。。。但我肯定不是在这里。。。尝试建议内部和受保护的构造函数?构造函数,该构造函数只能从库(程序集)访问,不能从其他库中的任何派生类型访问。也许我们可以区分“内部保护”和“内部保护”修饰符。所以第二个意思是它首先是“内部的”,然后才是“受保护的”。任何派生类(“protected”)和内部任何地方(现在)都可以使用原始方法。是否有任何生成后事件工具允许在编译后修改IL代码以获得所需的结果?只有当protected
属性的类型为public
,如string[]
时,它才有效。如果受保护
属性的类型本身是内部
,则编译失败,并显示消息不一致的可访问性:属性类型“Library.A”比属性“Library.OnlineStatusReport.Headers”更难访问。内部类不必是静态的,就可以用于受保护的内部类。我使用了您的想法,但在父类中,我有用于访问“受保护的内部”成员的内部类的实例。如果与internal
:internal override string[]Headers{get{return Headers;}private protected set{Headers=value;}结合使用,它确实可以允许读取
将是仅内部读取和仅内部保护写入。其他组合也是可能的。