具有访问该类中internal protected成员的能力

时间:2022-01-14 03:41:28

去年12月份,跟着Visual Studio 2017 Update 15.5的颁布,Visual C#迎来了它的最新版本:7.2. 在这个版本中,有个让人难以理解的新特性,就是private protected访谒修饰符(Access Modifier)。至此,C#语言的访谒修饰符有以下几种:

private

protected

public

internal

internal protected

private protected

既然有了private和protected,那么private protected又是什么?它跟internal protected又有什么关系?本文简单介绍一下。

private protected是怎么回事

在解释private protected之前,首先让我们回顾一下internal protected访谒修饰符。internal protected暗示,不异措施集(Assembly)中的其它类型,或者当前类的子类,具有访谒该类中internal protected成员的能力,可以用下图暗示:

具有访问该类中internal protected成员的能力

在上图中:

措施集A中的X类,可以访谒A类中的Method要领

措施集A中的B类,可以重载A类中的Method要领,B类中的其它成员也可以访谒A类中的Method

措施集B中的C类,可以重载A类中的Method要领,C类中的其它成员也可以通过base.Method()访谒A类中的Method

措施集B中C类的Method要领重载了A类的Method要领,因此,internal关键字被去失,于是,措施集B中的Y类,无法访谒C类中的Method要领

因此,internal protected暗示internal或者protected。

然而,private protected暗示,仅有不异措施集(Assembly)中担任于当前类型的类,才华访谒该类中private protected成员。换句话说,private protected就是访谒者必需在不异措施集中(internal),同时还必需是被访谒类型的子类(protected),可以用下图暗示:

具有访问该类中internal protected成员的能力

因此,private protected暗示internal并且protected。

private protected何时使用

理论上讲,private protected完善了C#语言的封装性,供给了另一层级另外成员访谒掩护,听起来觉得让人费解又没什么用。那么,什么时候使用这个访谒修饰符呢?现假设你正在设计一个框架,此中有个类,它供给东西存储成果,它的职责是生存给定的东西,而它的每一种实现都需要依赖于一个东西的序列化机制,好比:

public sealed class SerializationHelper { public string Serialze(object s) { using (var memoryStream = new MemoryStream()) { var serializer = new XmlSerializer(s.GetType()); serializer.Serialize(memoryStream, s); return Encoding.UTF8.GetString(memoryStream.ToArray()); } } } public abstract class DataStorage { private readonly SerializationHelper serializer = new SerializationHelper(); protected SerializationHelper Serializer => serializer; protected abstract void SaveObject(object obj); } public sealed class InMemoryDataStorage : DataStorage { private readonly List<string> serializedData = new List<string>(); protected override void SaveObject(object obj) => serializedData.Add(Serializer.Serialze(obj)); }

上面的代码中,SerializationHelper供给了一种将东西序列化成XML字符串的机制;DataStorage是所有东西数据存储的基类,它固然也为其子类供给了一个访谒东西序列化器的方法。由于这个东西序列化器是供给给其子类挪用的,因此,DataStorage中的Serializer属性是protected的。最后,InMemoryDataStorage担任了DataStorage,通过挪用由基类供给的Serializer属性,实现了SaveObject要领。

整个实现固然没有问题。可是,通过审核所有类型的可见性,我们发明,我们不筹算将SerializationHelper这个类袒露给外界,也就是不但愿其它的措施集能够直接访谒SerializationHelper类,于是,我们将它设置成internal的。也就是:

internal sealed class SerializationHelper { public string Serialze(object s) { using (var memoryStream = new MemoryStream()) { var serializer = new XmlSerializer(s.GetType()); serializer.Serialize(memoryStream, s); return Encoding.UTF8.GetString(memoryStream.ToArray()); } } }

好了,问题来了,编译器开始诉苦了,说SerializationHelper类的访谒级别比DataStorage.Serializer属性的访谒级别要低:

具有访问该类中internal protected成员的能力

原理显而易见:DataStorage.Serializer属性在DataStorage的子类中即可访谒,这个子类可以是在DataStorage地址的措施集中,也可以是在另一个措施集中。然而,这个属性的依赖类型:SerializationHelper类,却只能在DataStorage地址的措施集中才华被访谒。

于是,能量巨大的private protected闪亮登场。将DataStorage.Serializer属性的访谒修饰符从protected改为private protected,问题就解决了:

internal sealed class SerializationHelper { public string Serialze(object s) { using (var memoryStream = new MemoryStream()) { var serializer = new XmlSerializer(s.GetType()); serializer.Serialize(memoryStream, s); return Encoding.UTF8.GetString(memoryStream.ToArray()); } } } public abstract class DataStorage { private readonly SerializationHelper serializer = new SerializationHelper(); private protected SerializationHelper Serializer => serializer; protected abstract void SaveObject(object obj); } public sealed class InMemoryDataStorage : DataStorage { private readonly List<string> serializedData = new List<string>(); protected override void SaveObject(object obj) => serializedData.Add(Serializer.Serialze(obj)); }

不过,一旦使用了private protected访谒修饰符,,DataStorage.Serializer属性就只能在DataStorage地址的措施集的子类中访谒了。

private protected如何使用