在Kathleen Dollard最近的博客文章中,她提出了一个在.net中使用嵌套类的有趣理由.但是,她还提到FxCop不喜欢嵌套类.我假设编写FxCop规则的人并不愚蠢,所以必须在该位置背后有推理,但我无法找到它.
当您要嵌套的类仅对封闭类有用时,请使用嵌套类.例如,嵌套类允许您编写类似(简化)的内容:
public class SortedMap { private class TreeNode { TreeNode left; TreeNode right; } }
您可以在一个地方完成您的课程的完整定义,您不必跳过任何PIMPL箍来定义您的课程的工作方式,外部世界不需要查看您的实施内容.
如果TreeNode类是外部的,您可能必须创建所有字段public
或使用一堆get/set
方法来使用它.外面的世界会有另一个阶级污染他们的智力感知.
来自Sun的Java教程:
为什么使用嵌套类?使用嵌套类有几个令人信服的理由,其中包括:
这是一种逻辑分组仅在一个地方使用的类的方法.
它增加了封装.
嵌套类可以使代码更具可读性和可维护性.
类的逻辑分组 - 如果一个类只对另一个类有用,那么将它嵌入该类并将两者保持在一起是合乎逻辑的.嵌套这样的"帮助类"使得它们的包更加简化.
增加封装 - 考虑两个顶级类A和B,其中B需要访问A的成员,否则这些成员将被声明为私有.通过将类B隐藏在类A中,可以将A的成员声明为私有,并且B可以访问它们.另外,B本身可以隐藏在外面.< - 这不适用于C#的嵌套类实现,这仅适用于Java.
更易读,可维护的代码 - 在顶级类中嵌套小类会使代码更接近于使用它的位置.
完全懒惰和线程安全的单例模式
public sealed class Singleton { Singleton() { } public static Singleton Instance { get { return Nested.instance; } } class Nested { // Explicit static constructor to tell C# compiler // not to mark type as beforefieldinit static Nested() { } internal static readonly Singleton instance = new Singleton(); } }
来源:http://www.yoda.arachsys.com/csharp/singleton.html
这取决于用途.我很少会使用Public嵌套类,但始终使用Private嵌套类.私有嵌套类可用于仅在父级内部使用的子对象.例如,如果HashTable类包含仅在内部存储数据的私有Entry对象.
如果该类要由调用者(外部)使用,我通常喜欢将它作为一个单独的独立类.
除了上面列出的其他原因之外,还有一个原因,我不仅可以考虑使用嵌套类,还可以考虑使用公共嵌套类.对于那些使用共享相同泛型类型参数的多个泛型类的人来说,声明泛型命名空间的能力非常有用.不幸的是,.Net(或至少C#)不支持通用名称空间的概念.因此,为了实现相同的目标,我们可以使用泛型类来实现相同的目标.以下示例类与逻辑实体相关:
public class BaseDataObject < tDataObject, tDataObjectList, tBusiness, tDataAccess > where tDataObject : BaseDataObjectwhere tDataObjectList : BaseDataObjectList , new() where tBusiness : IBaseBusiness where tDataAccess : IBaseDataAccess { } public class BaseDataObjectList < tDataObject, tDataObjectList, tBusiness, tDataAccess > : CollectionBase where tDataObject : BaseDataObject where tDataObjectList : BaseDataObjectList , new() where tBusiness : IBaseBusiness where tDataAccess : IBaseDataAccess { } public interface IBaseBusiness < tDataObject, tDataObjectList, tBusiness, tDataAccess > where tDataObject : BaseDataObject where tDataObjectList : BaseDataObjectList , new() where tBusiness : IBaseBusiness where tDataAccess : IBaseDataAccess { } public interface IBaseDataAccess < tDataObject, tDataObjectList, tBusiness, tDataAccess > where tDataObject : BaseDataObject where tDataObjectList : BaseDataObjectList , new() where tBusiness : IBaseBusiness where tDataAccess : IBaseDataAccess { }
我们可以通过使用通用命名空间(通过嵌套类实现)来简化这些类的签名:
public partial class Entity < tDataObject, tDataObjectList, tBusiness, tDataAccess > where tDataObject : Entity.BaseDataObject where tDataObjectList : Entity .BaseDataObjectList, new() where tBusiness : Entity .IBaseBusiness where tDataAccess : Entity .IBaseDataAccess { public class BaseDataObject {} public class BaseDataObjectList : CollectionBase {} public interface IBaseBusiness {} public interface IBaseDataAccess {} }
然后,通过使用Erik van Brakel在之前的注释中建议的部分类,您可以将类分成单独的嵌套文件.我建议使用像NestIn这样的Visual Studio扩展来支持嵌套部分类文件.这允许"名称空间"类文件也用于组织文件夹中的嵌套类文件.
例如:
Entity.cs
public partial class Entity < tDataObject, tDataObjectList, tBusiness, tDataAccess > where tDataObject : Entity.BaseDataObject where tDataObjectList : Entity .BaseDataObjectList, new() where tBusiness : Entity .IBaseBusiness where tDataAccess : Entity .IBaseDataAccess { }
Entity.BaseDataObject.cs
partial class Entity{ public class BaseDataObject { public DataTimeOffset CreatedDateTime { get; set; } public Guid CreatedById { get; set; } public Guid Id { get; set; } public DataTimeOffset LastUpdateDateTime { get; set; } public Guid LastUpdatedById { get; set; } public static implicit operator tDataObjectList(DataObject dataObject) { var returnList = new tDataObjectList(); returnList.Add((tDataObject) this); return returnList; } } }
Entity.BaseDataObjectList.cs
partial class Entity{ public class BaseDataObjectList : CollectionBase { public tDataObjectList ShallowClone() { var returnList = new tDataObjectList(); returnList.AddRange(this); return returnList; } } }
Entity.IBaseBusiness.cs
partial class Entity{ public interface IBaseBusiness { tDataObjectList Load(); void Delete(); void Save(tDataObjectList data); } }
Entity.IBaseDataAccess.cs
partial class Entity{ public interface IBaseDataAccess { tDataObjectList Load(); void Delete(); void Save(tDataObjectList data); } }
然后,visual studio解决方案资源管理器中的文件将按如下方式组织:
Entity.cs + Entity.BaseDataObject.cs + Entity.BaseDataObjectList.cs + Entity.IBaseBusiness.cs + Entity.IBaseDataAccess.cs
您将实现通用命名空间,如下所示:
User.cs
public partial class User : Entity < User.DataObject, User.DataObjectList, User.IBusiness, User.IDataAccess > { }
User.DataObject.cs
partial class User { public class DataObject : BaseDataObject { public string UserName { get; set; } public byte[] PasswordHash { get; set; } public bool AccountIsEnabled { get; set; } } }
User.DataObjectList.cs
partial class User { public class DataObjectList : BaseDataObjectList {} }
User.IBusiness.cs
partial class User { public interface IBusiness : IBaseBusiness {} }
User.IDataAccess.cs
partial class User { public interface IDataAccess : IBaseDataAccess {} }
这些文件将在解决方案资源管理器中进行组织,如下所示:
User.cs + User.DataObject.cs + User.DataObjectList.cs + User.IBusiness.cs + User.IDataAccess.cs
以上是使用外部类作为通用名称空间的简单示例.我在过去构建了包含9个或更多类型参数的"通用名称空间".必须在所有需要知道类型参数的九种类型中保持这些类型参数同步是繁琐的,特别是在添加新参数时.通用命名空间的使用使得代码更易于管理和读取.