您能否解释一下实际用途是什么 internal C# 中的关键字?

我知道 internal 修饰符限制对当前程序集的访问,但是何时以及在什么情况下应该使用它?

有帮助吗?

解决方案

您希望从同一程序集中的许多其他类访问的实用程序或帮助程序类/方法,但是您希望确保其他程序集中的代码无法访问。

来自 MSDN (通过archive.org):

  

内部访问的一个常见用途是基于组件的开发,因为它使一组组件能够以私有方式进行协作,而不会暴露给其他应用程序代码。例如,用于构建图形用户界面的框架可以提供使用具有内部访问权限的成员进行协作的Control和Form类。由于这些成员是内部成员,因此不会暴露给使用该框架的代码。

您还可以使用内部修饰符以及用于创建“朋友”的 InternalsVisibleTo 程序集级别属性被授予对目标程序集内部类的特殊访问权限的程序集。

这对于创建单元测试程序集非常有用,然后允许它们调用要测试的程序集的内部成员。当然,没有其他程序集被授予此级别的访问权限,因此当您释放系统时,将保留封装。

其他提示

如果Bob需要BigImportantClass,那么Bob需要让拥有项目A的人员进行注册,以保证将编写BigImportantClass以满足他的需求,经过测试以确保满足他的需求,并记录为满足他的需求,以及将建立一个流程,以确保永远不会改变,以便不再满足他的需求。

如果一个类是内部的,那么它就不必经过那个过程,这样可以节省他们可以花在其他事情上的项目A的预算。

内部的要点不是让鲍勃生活困难。它允许您控制项目A对功能,生命周期,兼容性等所做的昂贵承诺。

使用内部的另一个原因是你混淆了你的二进制文件。混淆器知道对任何内部类的类名进行加密是安全的,而公共类的名称不能被加扰,因为这可能会破坏现有的引用。

如果您正在编写一个将大量复杂功能封装到一个简单的公共API中的DLL,那么“内部”用于不公开曝光的班级成员。

隐藏复杂性(a.k.a. encapsulation)是高质量软件工程的主要概念。

当您在非托管代码上构建包装器时,会大量使用internal关键字。

如果你有一个基于C / C ++的库你想要DllImport你可以将这些函数作为类的静态函数导入,并将它们作为内部函数,那么你的用户只能访问你的包装器而不是原始的API,所以它不能搞乱任何东西。这些函数是静态的,你可以在程序集中的任何地方使用它们,用于你需要的多个包装类。

你可以看看Mono.Cairo,它是使用这种方法的cairo库的包装器。

在“尽可能使用严​​格修饰符”规则的驱动下,我在需要访问的任何地方都使用内部,例如,从另一个类访问方法,直到我明确需要从另一个程序集访问它。

由于程序集接口通常比其类接口的总和更窄,所以我在很多地方使用它。

我发现内部被过度使用了。你真的不应该只将某些功能暴露给你不会对其他消费者的某些类别。

这在我看来打破了界面,打破了抽象。这并不是说它永远不应该被使用,但更好的解决方案是重构到不同的类或者如果可能的话以不同的方式使用。但是,这可能并不总是可行。

它可能导致问题的原因是另一个开发人员可能被指控在与您相同的程序集中构建另一个类。内部因素会降低抽象的清晰度,如果被滥用会导致问题。这就像你把它公之于众一样。其他开发人员正在构建的另一个类仍然是消费者,就像任何外部类一样。类抽象和封装不仅仅用于保护外部类,也适用于任何和所有类。

另一个问题是很多开发人员会认为他们可能需要在程序集的其他地方使用它并将其标记为内部,即使他们当时不需要它。然后另一位开发商可能认为它在那里。通常,您希望标记为私有,直到您有一个确定的需求。

但其中一些可能是主观的,我并不是说永远不应该使用它。只需在需要时使用。

前几天,也许是一周,在我不记得的博客上看到一个有趣的。基本上我不能相信这一点,但我认为它可能有一些有用的应用。

假设您希望另一个程序集看到一个抽象类,但您不希望某人能够从中继承它。密封将无法工作,因为它是抽象的原因,该程序集中的其他类确实从它继承。 Private将无法工作,因为您可能希望在另一个程序集中的某处声明Parent类。

namespace Base.Assembly
{
  public abstract class Parent
  {
    internal abstract void SomeMethod();
  }

  //This works just fine since it's in the same assembly.
  public class ChildWithin : Parent
  {
    internal override void SomeMethod()
    {
    }
  }
}

namespace Another.Assembly
{
  //Kaboom, because you can't override an internal method
  public class ChildOutside : Parent
  {
  }

  public class Test 
  { 

    //Just fine
    private Parent _parent;

    public Test()
    {
      //Still fine
      _parent = new 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的可访问性级别更改为内部。在这种情况下,您可以实例化该类,但无法访问内部成员。

// 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/en-us/library/7c5ka91b(VS.80).aspx

内部的一个非常有趣的用法 - 内部成员当然仅限于声明它的程序集 - 正在获得“朋友”。某种程度上的功能。友元成员只能在其声明的程序集之外的某些其他程序集中可见。 C#没有内置支持的朋友,但CLR确实如此。

您可以使用 InternalsVisibleToAttribute 声明一个朋友程序集,并且友元程序集中的所有引用都会将声明程序集的内部成员视为友元程序集范围内的公共成员。这样做的一个问题是所有内部成员都是可见的;你无法挑选。

InternalsVisibleTo的一个很好的用途是将各种内部成员暴露给单元测试程序集,从而消除了对复杂反射工作的需求以测试这些成员。所有可见的内部成员都不是一个问题,但是采用这种方法会严重破坏类接口,并且可能会破坏声明程序集中的封装。

当你有方法,类等需要在当前程序集的范围内访问时,从不在它之外。

例如,DAL可能具有ORM,但不应将对象暴露给业务层,所有交互都应通过静态方法完成,并传递所需的参数。

根据经验,有两种成员:

  • 公共表面:从外部程序集可见(公共、受保护和内部受保护):调用者不可信,因此参数验证、方法文档等。是需要的。
  • 私人表面:从外部程序集(私有和内部或内部类)不可见:调用者通常是可信的,因此参数验证、方法文档等。可以省略。

降噪,您公开的类型越少,您的库就越简单。 防篡改/安全是另一个(虽然反射可以赢得反对)。

内部类使您可以限制程序集的API。这样做有一些好处,比如让您的API更易于理解。

此外,如果程序集中存在错误,则修复程序引入重大更改的可能性较小。如果没有内部类,您将不得不假设更改任何类的公共成员将是一个重大变化。对于内部类,您可以假设修改其公共成员只会破坏程序集的内部API(以及InternalsVisibleTo属性中引用的任何程序集)。

我喜欢在类级别和程序集级别进行封装。有些人不同意这一点,但很高兴知道功能可用。

我有一个项目,它使用LINQ-to-SQL作为数据后端。我有两个主要的命名空间:Biz和Data。 LINQ数据模型存在于数据中并标记为“内部”; 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 或<代码>私人,没有具体原因。

我唯一使用过内部关键字的是我产品中的许可证检查代码; - )

internal关键字的一个用途是限制对程序集用户的具体实现的访问。

如果您有一个工厂或其他中心位置来构建对象,那么程序集的用户只需要处理公共接口或抽象基类。

此外,内部构造函数允许您控制实例化其他公共类的位置和时间。

这个怎么样:通常建议您不要将List对象公开给程序集的外部用户,而是公开IEnumerable。但是在程序集中使用List对象要容易得多,因为您获得了数组语法和所有其他List方法。因此,我通常有一个内部属性,公开要在程序集中使用的List。

欢迎对这种方法发表评论。

请记住,当有人查看您的项目命名空间时,任何定义为 public 的类都会自动显示在intellisense中。从API的角度来看,重要的是只向项目用户显示他们可以使用的类。使用 internal 关键字隐藏他们不应该看到的内容。

如果项目A的 Big_Important_Class 打算在项目之外使用,则不应将其标记为 internal

但是,在许多项目中,您通常会拥有真正仅用于项目内部的类。例如,您可能有一个类,其中包含参数化线程调用的参数。在这些情况下,如果没有其他原因,您应该将它们标记为 internal ,而不是保护自己免受意外的API更改。

这个想法是,当你设计一个库时,只有那些打算在外面使用的类(由你的库的客户端)应该是公共的。这样你就可以隐藏那些

的类
  1. 在将来的版本中可能会发生变化(如果它们是公开的,则会破坏客户端代码)
  2. 对客户无用,可能会引起混淆
  3. 不安全(因此使用不当可能会严重破坏您的图书馆)
  4. 如果您正在开发内部解决方案而不是使用内部元素我认为并不重要,因为通常客户将与您保持持续联系和/或访问代码。但它们对于图书馆开发者来说相当重要。

当你的类或方法不能完全适合面向对象的范例时,它会做危险的事情,需要从你控制的其他类和方法调用,而你不想让它们其他人都在使用。

public class DangerousClass {
    public void SafeMethod() { }
    internal void UpdateGlobalStateInSomeBizarreWay() { }
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top