热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C#学习教程:在C#中使用内部类分享

在C#中使用内部类关于C#中内部类的使用和结构的最佳实践是什么?例如,如果我有一个非常大的基类和两个大的内部类,我应该将它们分成单独的(部分类)代码文件,还是将它们作为一个非常大的

在C#中使用内部类

关于C#中内部类的使用和结构的最佳实践是什么?

例如,如果我有一个非常大的基类和两个大的内部类,我应该将它们分成单独的(部分类)代码文件,还是将它们作为一个非常大的笨重的代码文件?

拥有一个公共inheritance的内部类的抽象类也是不好的做法吗?

通常我会为以下两个目的之一保留内部类:

  1. 从其父类派生的公共类,其中父类是具有一个或多个抽象方法的抽象基础实现,每个子类是为特定实现提供服务的实现。 在阅读框架设计和指南之后,我看到它被标记为“避免”,但我在类似于枚举的场景中使用它 – althogh也可能给人留下不好的印象

  2. 内部类是私有的,是业务逻辑的单元,或者以其他方式紧密耦合到它们的父类,它们在被任何其他类消费或使用时从根本上被破坏。

对于所有其他情况,我尝试将它们保持在与其使用者/逻辑父级相同的命名空间和相同的可访问级别 – 通常使用比“主”类稍微不友好的名称。

在大型项目中,您会惊讶地发现自己最初构建一个强耦合组件的频率是因为它的第一个或主要目的使它看起来合乎逻辑 – 但除非您有非常好或技术上的理由将其锁定并隐藏从视线开始,暴露课程几乎没有什么害处,以便其他组件可以消耗它。

编辑请记住,即使我们谈论的是子类,它们应该是设计得很好或松散耦合的组件。 即使它们是私有的并且对于外部世界是不可见的,在类之间保持最小的“表面区域”将极大地简化代码的可维护性,以便将来扩展或更改。

我没有这本书,但框架设计指南建议使用public内部类,只要客户不必引用类名。 private内部阶级很好:没有人会注意到这些。

错误: ListView.ListViewItemCollection collection = new ListView.ListViewItemCollection();

好: listView.Items.Add(...);

关于你的大class:通常有必要将这样的东西分成更小的类,每个类都有一个特定的function。 最初很难打破它,但我预测它会让你的生活更轻松……

通常,内部类应该是私有的,并且只能由包含它们的类使用。 如果他们的内部类非常大,则表明他们应该是他们自己的类。

通常当你有一个很大的内部类时,它是因为内部类与它的包含类紧密耦合,需要访问其私有方法。

我认为这是相当主观的,但我可能会通过将“host”类局部化而将它们拆分为单独的代码文件。

通过这样做,您可以通过编辑项目文件来获得更多概述,使文件组与Windows窗体中的设计器类一样。 我想我已经看过一个Visual Studio插件,可以自动为你做这个,但我不记得在哪里。

编辑:
经过一番观察,我找到了用于执行此操作的Visual Studio加载项,称为VSCommands

仅关于如何构建这样的野兽……

您可以使用部分类来拆分主类和嵌套类。 当您这样做时,建议您恰当地命名文件,以便明显发生了什么。

 // main class in file Outer.cs namespace Demo { public partial class Outer { // Outer class } } // nested class in file Outer.Nested1.cs namespace Demo { public partial class Outer { private class Nested1 { // Nested1 details } } } 

以同样的方式,您经常在自己的文件中看到(显式)接口。 例如Outer.ISomeInterface.cs而不是编辑器默认的#region ing。

您的项目文件结构然后开始看起来像

     /Project/Demo/ISomeInterface.cs     /Project/Demo/Outer.cs     /Project/Demo/Outer.Nested1.cs     /Project/Demo/Outer.ISomeInterface.cs 

通常,当我们这样做时,它是针对Builder模式的变体。

我个人喜欢每个文件有一个类,内部类作为该文件的一部分。 我认为内部类通常(几乎总是)是私有的,并且是类的实现细节。 将它们放在一个单独的文件中会让人感到困惑,IMO。

在这种情况下,使用代码区域来包裹内部类并隐藏它们的细节对我来说很有效,并且使文件难以使用。 代码区域保持内部类“隐藏”,因为它是私有的实现细节,这对我来说没问题。

我个人使用内部类来封装一些仅在内部使用的概念和操作。 这样我就不会污染那个class级的’非公开api,并保持api清洁和紧凑。

您可以利用部分类将这些内部类的定义移动到不同的文件中,以便更好地组织。 除了一些模板化项目(如ASP.NET,WinForm表单等)之外,VS不会自动为您分组部分类文件。您需要编辑项目文件并在其中进行一些更改。 您可以查看其中一个现有分组,了解它是如何完成的。 我相信有一些宏允许您在解决方案资源管理器中为您分组部分类文件。

在我看来,如果需要的话,内部类应该保持较小并且仅在该类内部使用。 如果在.NET框架上使用Relfector,您会看到它们仅用于此目的。

如果你的内部类太大了,我肯定会以某种方式将它们移到单独的类/代码文件中,如果只是为了可维护性。 我必须支持一些现有的代码,有人认为在内部类中使用内部类是个好主意。 它导致内部类层次结构运行深度为4到5级。 不用说代码是不可穿透的,需要很长时间才能理解你在看什么。

这里看一个嵌套类的实际例子,它可以让你知道它们的用途(添加了一些unit testing)

上述就是C#学习教程:在C#中使用内部类分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—编程笔记

 namespace CoreLib.Helpers { using System; using System.Security.Cryptography; public static class Rnd { private static readonly Random _random = new Random(); public static Random Generator { get { return _random; } } static Rnd() { } public static class Crypto { private static readonly RandomNumberGenerator _highRandom = RandomNumberGenerator.Create(); public static RandomNumberGenerator Generator { get { return _highRandom; } } static Crypto() { } } public static UInt32 Next(this RandomNumberGenerator value) { var bytes = new byte[4]; value.GetBytes(bytes); return BitConverter.ToUInt32(bytes, 0); } } } [TestMethod] public void Rnd_OnGenerator_UniqueRandomSequence() { var rdn1 = Rnd.Generator; var rdn2 = Rnd.Generator; var list = new List(); var tasks = new Task[10]; for (var i = 0; i <10; i++) { tasks[i] = Task.Factory.StartNew((() => { for (var k = 0; k <1000; k++) { lock (list) { list.Add(Rnd.Generator.Next(Int32.MinValue, Int32.MaxValue)); } } })); } Task.WaitAll(tasks); var distinct = list.Distinct().ToList(); Assert.AreSame(rdn1, rdn2); Assert.AreEqual(10000, list.Count); Assert.AreEqual(list.Count, distinct.Count); } [TestMethod] public void Rnd_OnCryptoGenerator_UniqueRandomSequence() { var rdn1 = Rnd.Crypto.Generator; var rdn2 = Rnd.Crypto.Generator; var list = new ConcurrentQueue(); var tasks = new Task[10]; for (var i = 0; i <10; i++) { tasks[i] = Task.Factory.StartNew((() => { for (var k = 0; k <1000; k++) { list.Enqueue(Rnd.Crypto.Generator.Next()); } })); } Task.WaitAll(tasks); var distinct = list.Distinct().ToList(); Assert.AreSame(rdn1, rdn2); Assert.AreEqual(10000, list.Count); Assert.AreEqual(list.Count, distinct.Count); } 


推荐阅读
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 使用nodejs爬取b站番剧数据,计算最佳追番推荐
    本文介绍了如何使用nodejs爬取b站番剧数据,并通过计算得出最佳追番推荐。通过调用相关接口获取番剧数据和评分数据,以及使用相应的算法进行计算。该方法可以帮助用户找到适合自己的番剧进行观看。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • 本文内容为asp.net微信公众平台开发的目录汇总,包括数据库设计、多层架构框架搭建和入口实现、微信消息封装及反射赋值、关注事件、用户记录、回复文本消息、图文消息、服务搭建(接入)、自定义菜单等。同时提供了示例代码和相关的后台管理功能。内容涵盖了多个方面,适合综合运用。 ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
author-avatar
无谓__
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有