C# 在C语言中使用内部类#
关于C#中内部类的使用和结构,有哪些最佳实践 例如,如果我有一个非常大的基类和两个很大的内部类,我应该将它们分割成单独的(部分类)代码文件,还是将它们作为一个非常大的笨拙的代码文件C# 在C语言中使用内部类#,c#,inner-classes,C#,Inner Classes,关于C#中内部类的使用和结构,有哪些最佳实践 例如,如果我有一个非常大的基类和两个很大的内部类,我应该将它们分割成单独的(部分类)代码文件,还是将它们作为一个非常大的笨拙的代码文件 使用公共继承的内部类创建抽象类也是一种不好的做法吗?通常,内部类应该是私有的,并且只能由包含它们的类使用。如果它们的内部类非常大,则表明它们应该是自己的类 通常,当您拥有一个大的内部类时,这是因为内部类与其包含的类紧密耦合,并且需要访问其私有方法 我认为这是相当主观的,但我可能会通过使“host”类部分化,将它们分成
使用公共继承的内部类创建抽象类也是一种不好的做法吗?通常,内部类应该是私有的,并且只能由包含它们的类使用。如果它们的内部类非常大,则表明它们应该是自己的类
通常,当您拥有一个大的内部类时,这是因为内部类与其包含的类紧密耦合,并且需要访问其私有方法 我认为这是相当主观的,但我可能会通过使“host”类部分化,将它们分成单独的代码文件 通过这样做,您可以获得更多的概述,使文件组与Windows窗体中的设计器类类似。我想我见过一个VisualStudio插件,它可以自动为您实现这一点,但我不记得在哪里 编辑:
查看了一番之后,我发现了一个名为VSCommands的VisualStudio插件,我手头没有这本书,但是框架设计指南建议使用
public
内部类,只要客户端不必引用类名<代码>私有内部类很好:没有人会注意到这些
错误:ListView.ListViewItemCollection集合=新建ListView.ListViewItemCollection()代码>
好:listView.Items.Add(…)代码>
关于您的大型类:一般来说,将类似这样的内容拆分为较小的类是值得的,每个类都有一个特定的功能。最初很难将其分解,但我预测它会使您以后的生活更轻松…我个人喜欢每个文件有一个类,内部类作为该文件的一部分。我认为内部类通常(几乎总是)应该是私有的,并且是类的一个实现细节。在我看来,把它们放在一个单独的文件中会使事情变得混乱
在本例中,使用代码区域环绕内部类并隐藏其详细信息对我来说效果很好,并且避免了文件难以处理。代码区域将内部类保持为“隐藏”,因为它是一个私有实现细节,这对我来说很好。通常我保留内部类用于以下两个目的之一:
从其父类派生的公共类,其中父类是具有一个或多个抽象方法的抽象基实现,每个子类是为特定实现服务的实现。在阅读了框架设计和指南之后,我看到它被标记为“避免”,但是我在类似于枚举的场景中使用它——尽管这可能也会给人留下不好的印象
内部类是私有的,是业务逻辑的单元,或者以某种方式紧密地耦合到它们的父类,在被任何其他类消费或使用时,它们从根本上被破坏
对于所有其他情况,我尝试将它们与它们的使用者/逻辑父类保持在相同的名称空间和相同的可访问性级别中——通常使用比“main”类稍微不友好的名称
在大型项目中,您可能会惊讶地发现,您最初构建强耦合组件的频率是如此之高,仅仅因为它的第一个或主要目的使它看起来是合乎逻辑的——然而,除非您有很好的或技术上的理由将其锁定并隐藏起来,否则将该类公开以使其他类组件可以使用它
编辑请记住,即使我们讨论的是子类,它们也应该或多或少是设计良好、松散耦合的组件。即使它们是私有的,外部世界看不见,在类之间保留一个最小的“表面积”将极大地降低代码的可维护性,以便将来扩展或修改。我个人使用内部类来封装一些仅在类内部使用的概念和操作。这样我就不会污染该类的非公共api,并保持api干净紧凑
您可以利用分部类将这些内部类的定义移动到不同的文件中,以便更好地组织。VS不会自动为您分组部分类文件,但某些模板化项目除外,如ASP.NET、WinForm表单等。您需要编辑项目文件并在其中进行一些更改。您可以查看其中的一个现有分组,了解它是如何完成的。我相信有一些宏允许您在解决方案资源管理器中为您分组部分类文件。仅涉及如何构造这样的beast
可以使用分部类拆分主类和嵌套类。当您这样做时,建议您适当地命名文件,以便清楚地知道发生了什么
// 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
}
}
}
同样,您经常在自己的文件中看到(显式)接口。e、 g.Outer.isomoInterface.cs
而不是编辑器默认的#region
对其进行编辑
然后,您的项目文件结构开始如下所示
/Project/Demo/ISomeInterface.cs
/Project/Demo/Outer.cs
/Project/Demo/Outer.Nested1.cs
/Project/Demo/Outer.ISomeInterface.cs
/Project/Demo/interface.cs
/Project/Demo/Outer.cs
/Project/Demo/Outer.Nested1.cs
/Project/Demo/Outer.interface.cs
通常,当我们这样做时,它是用于构建器模式的变体。在我看来,内部类(如果需要的话)应该保持较小,并且只由该类在内部使用。如果您在.NET framework上使用Relfector,您会看到它们正是为了这个目的而大量使用的
如果您的内部类变得太大,我肯定会以某种方式将它们移出到单独的类/代码文件中,如果只是为了可维护性的话。我必须支持一些现实
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<Int32>();
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<UInt32>();
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);
}