您能否解释一下internal
C#中关键字的实际用法?
我知道internal
修饰符会限制对当前程序集的访问,但是我应该在何时何地使用它?
您能否解释一下internal
C#中关键字的实际用法?
我知道internal
修饰符会限制对当前程序集的访问,但是我应该在何时何地使用它?
Answers:
您希望从同一程序集中的许多其他类访问的实用程序或帮助程序类/方法,但是要确保其他程序集中的代码无法访问。
从MSDN(通过archive.org):
内部访问的常见用法是在基于组件的开发中,因为它使一组组件能够以私有方式进行协作,而不会暴露给其余的应用程序代码。例如,用于构建图形用户界面的框架可以提供Control和Form类,这些类使用具有内部访问权限的成员进行协作。由于这些成员是内部成员,因此它们不会接触使用该框架的代码。
您还可以将内部修饰符与InternalsVisibleTo
程序集级别属性一起使用,以创建“朋友”程序集,这些程序集被授予对目标程序集内部类的特殊访问权限。
这对于创建单元测试程序集很有用,然后允许其调用要测试的程序集的内部成员。当然,没有其他程序集被授予此访问级别,因此,在释放系统时,将维护封装。
如果Bob需要BigImportantClass,则Bob需要让拥有项目A的人员进行签名,以确保将BigImportantClass编写为满足他的需求,并进行测试以确保它满足他的需求,并被记录为满足他的需求,并且该过程将会就位,以确保它永远不会改变,从而不再满足他的需求。
如果一个类是内部类,则不必经过该过程,从而节省了项目A的预算,他们可以将其用于其他事情。
内部的意义不是鲍勃的生活困难。这是因为它允许您控制Project A在功能,寿命,兼容性等方面做出的昂贵承诺。
使用internal的另一个原因是如果您混淆了二进制文件。混淆器知道对任何内部类的类名称进行加密是安全的,而对公共类的名称则不能进行加密,因为这可能会破坏现有的引用。
当您在非托管代码上构建包装器时,将大量使用internal关键字。
当您具有要DllImport的基于C / C ++的库时,可以将这些函数作为类的静态函数导入,并使它们成为内部函数,因此您的用户只能访问包装器,而不能访问原始API,因此它不能搞砸了。这些函数是静态的,您可以在程序集中的任何地方使用它们,以获取所需的多个包装器类。
您可以看一下Mono.Cairo,它是使用这种方法的cairo库的包装。
在“尽可能使用严格的修饰符”规则的驱使下,我在需要访问另一个类的方法的所有地方使用内部,直到我明确需要从另一个程序集访问它为止。
由于汇编接口通常比其类接口的总和还要狭窄,因此在很多地方都可以使用它。
我发现内部使用过多。您确实不应仅将某些功能暴露于某些类,而不会暴露给其他使用者。
我认为这破坏了接口,破坏了抽象。这并不是说永远不应该使用它,而是更好的解决方案是重构到不同的类或在可能的情况下以不同的方式使用。但是,这并非总是可能的。
可能导致问题的原因是,另一个开发人员可能要负责在与您相同的程序集中构建另一个类。具有内部结构会降低抽象的清晰度,并且如果滥用会导致问题。就像您将其公开一样,这将是同样的问题。就像任何外部类一样,由其他开发人员构建的另一个类仍然是使用者。类抽象和封装并不是仅用于保护外部类,也不能用于外部类,而是用于任何和所有类。
另一个问题是,许多开发人员会认为他们可能需要在程序集中的其他位置使用它,并且无论如何都将其标记为内部,即使他们当时不需要它。然后,另一位开发人员可能会认为它值得一试。通常,您希望在没有明确需求之前将其标记为私有。
但是其中一些可能是主观的,我并不是说永远不要使用它。只需在需要时使用。
前几天,也许是一周,在一个我不记得的博客上看到了一个有趣的故事。基本上,我不能为此付出功劳,但我认为它可能会有一些有用的应用程序。
假设您希望一个抽象类可以被另一个程序集看到,但是您不希望某人能够从该类继承。Sealed无法工作,因为它是抽象的,这是有原因的,该程序集中的其他类确实会继承自它。私有不起作用,因为您可能想在另一个程序集中的某个地方声明一个Parent类。
名称空间Base.Assembly { 公共抽象类家长 { 内部抽象void SomeMethod(); } //由于在同一程序集中,因此效果很好。 公共类ChildWithin:父母 { 内部重写void SomeMethod() { } } } 命名空间Another.Assembly { // Kaboom,因为您无法覆盖内部方法 公共课程ChildOutside:家长 { } 公共课测验 { //正好 私人父母_parent; 公共测试 { //还是不错 _parent =新的ChildWithin(); } } }
如您所见,它有效地允许某人使用Parent类而不能从其继承。
本示例包含两个文件:Assembly1.cs和Assembly2.cs。第一个文件包含一个内部基类BaseClass。在第二个文件中,尝试实例化BaseClass将产生一个错误。
// Assembly1.cs
// compile with: /target:library
internal class BaseClass
{
public static int intM = 0;
}
// Assembly1_a.cs
// compile with: /reference:Assembly1.dll
class TestAccess
{
static void Main()
{
BaseClass myBase = new BaseClass(); // CS0122
}
}
在此示例中,使用与示例1中相同的文件,并将BaseClass的可访问性级别更改为public。还将成员IntM的可访问性级别更改为internal。在这种情况下,您可以实例化该类,但不能访问内部成员。
// Assembly2.cs
// compile with: /target:library
public class BaseClass
{
internal static int intM = 0;
}
// Assembly2_a.cs
// compile with: /reference:Assembly1.dll
public class TestAccess
{
static void Main()
{
BaseClass myBase = new BaseClass(); // Ok.
BaseClass.intM = 444; // CS0117
}
}
来源:http : //msdn.microsoft.com/zh-cn/library/7c5ka91b(VS.80).aspx
内部的一种非常有趣的用法-内部成员当然仅限于声明它的程序集-在某种程度上从中获得“朋友”功能。朋友成员是仅在声明其的程序集之外的某些其他程序集可见的东西。C#没有内置的对Friend的支持,但是CLR却支持。
您可以使用InternalsVisibleToAttribute声明一个朋友程序集,并且该朋友程序集中的所有引用都将在朋友程序集范围内将声明程序集的内部成员视为公共程序。一个问题是所有内部成员都是可见的。你不能选择。
InternalsVisibleTo的一个很好的用途是将各种内部成员暴露给一个单元测试程序集,从而消除了测试这些成员所需的复杂反射工作。所有内部成员可见并不是什么大问题,但是采用这种方法确实会严重破坏类接口,并可能破坏声明程序集中的封装。
作为经验法则,成员有两种:
我有一个使用LINQ-to-SQL作为数据后端的项目。我有两个主要的命名空间:Biz和Data。LINQ数据模型位于Data中,并标记为“内部”。Biz名称空间具有公共类,这些公共类包装了LINQ数据类。
所以有Data.Client
和Biz.Client
; 后者公开了数据对象的所有相关属性,例如:
private Data.Client _client;
public int Id { get { return _client.Id; } set { _client.Id = value; } }
Biz对象具有一个私有构造函数(强制使用工厂方法)和一个内部构造函数,如下所示:
internal Client(Data.Client client) {
this._client = client;
}
库中的任何业务类都可以使用该类,但是前端(UI)无法直接访问数据模型,从而确保业务层始终充当中介。
这是我第一次真正使用internal
很多东西,并且证明它非常有用。
在某些情况下,使类的成员有意义internal
。例如,如果您想控制如何实例化类,就可以使用一个示例。假设您提供了某种工厂来创建类的实例。您可以创建构造函数internal
,以便工厂(位于同一程序集中)可以创建该类的实例,但该程序之外的代码则不能。
但是,在internal
没有特定原因的情况下创建类或成员,就没有什么意义public
,或者在private
没有特定原因的情况下创建类或成员,我看不到任何意义。
这个怎么样:通常建议您不要向程序集的外部用户公开List对象,而应公开IEnumerable。但是,在程序集中使用List对象要容易得多,因为可以获得数组语法和所有其他List方法。因此,我通常具有一个内部属性,该属性公开了要在程序集中使用的List。
欢迎对此方法发表评论。
请记住,定义为的任何类public
都会在有人查看您的项目名称空间时自动显示在智能感知中。从API角度来看,仅向项目用户显示他们可以使用的类非常重要。使用internal
关键字隐藏他们不应该看到的东西。
如果您Big_Important_Class
的Project A项目打算在项目外部使用,则您不应对其进行标记internal
。
但是,在许多项目中,您经常会遇到实际上仅打算在项目内部使用的类。例如,您可能有一个类,用于保存参数化线程调用的参数。在这些情况下,您应该将它们标记为internal
仿佛没有其他原因,除了保护自己免受将来意外的API更改之外。
private
关键字只能在被另一个类或结构内定义的类或结构一起使用。在命名空间中定义的类只能声明public
或internal
。
当您遇到的类或方法不完全适合于面向对象的范式,执行危险的事情,需要从您控制下的其他类和方法中调用它们并且不想让其他任何人使用时。
public class DangerousClass {
public void SafeMethod() { }
internal void UpdateGlobalStateInSomeBizarreWay() { }
}