2008-10-03 22 views

回答

286

工具或輔助類/你想從許多其他類相同的組件內訪問方法,但要保證在其他組件的代碼無法訪問。

MSDN

一個常見用途的內部連接在基於組件的開發,因爲它使一組部件在一個私人方式而不暴露給應用程序代碼的其餘部分配合的。例如,構建圖形用戶界面的框架可以提供Control和Form類,這些類可以使用具有內部訪問權限的成員進行合作。由於這些成員是內部的,它們不會暴露於使用該框架的代碼。

您也可以使用內部修改與InternalsVisibleTo彙編級屬性一起創建授予目標總成內部類特殊通道「朋友」組件。

這可以用於創建單元測試程序集,然後允許調用要測試的程序集的內部成員。當然,沒有其他程序集被授予這種級別的訪問權限,所以當你釋放你的系統時,封裝是保持不變的。

+6

InternalsVisibleTo屬性是一個很好的幫助。謝謝。 – erict 2011-11-08 21:11:22

+16

我的感覺是,從你需要內部的那一刻起,某個地方的設計出現了問題。恕我直言,一個應該能夠使用純OO來解決所有問題。在這一刻,我盯着.NET Framework源代碼中內部的第一百萬次使用,禁止我利用自己使用的內容。通過使用內部,他們創建了一個表面模塊化的巨石,但是當你試圖分離東西時會崩潰。另外,安全並不是一個爭論,因爲這反映了救援。 – 2012-10-18 12:32:34

+1

一般來說,我同意你的看法。唯一的例外是能夠在不必創建私有訪問器的情況下構建單元測試。如果你想檢查一個特定的依賴關係是否正確分配,並且包含該依賴關係的字段是不可公開訪問的,那麼使用internal就是要走的路。 – 2013-02-12 21:35:55

-5

當你的類或方法不適合乾淨地插入面向對象的範式時,它會做出危險的東西,這些東西需要在你控制下的其他類和方法中調用,而你不想讓其他人使用。

public class DangerousClass { 
    public void SafeMethod() { } 
    internal void UpdateGlobalStateInSomeBizarreWay() { } 
} 
+0

你到底想說什麼呢?這不是很清楚。至少不是我。 – pqsk 2012-09-06 12:54:06

5

當你有方法,類等需要在當前程序集的範圍內訪問,並且從不在外面。

例如,DAL可能具有ORM,但不應將對象暴露給業務層,所有交互都應通過靜態方法完成並傳入所需的參數。

9

我發現內部被過度使用。你真的不應該將某些功能暴露給某些你不會向其他消費者提供的功能。

這在我看來打破了界面,打破了抽象。這並不是說它永遠不會被使用,但更好的解決方案是重構不同的類,或者如果可能的話以不同的方式使用。但是,這可能不總是可能的。

它可能會導致問題的原因是,另一個開發人員可能會被要求在與您的相同程序集中構建另一個類。內部構件減少了抽象的清晰度,並且如果被濫用會導致問題。這將是同樣的問題,如果你公開。另一個開發人員正在構建的其他類仍然是一個消費者,就像任何外部類一樣。類抽象和封裝不僅用於保護/從外部類,而且用於任何類和所有類。

的另一個問題是,很多開發商將認爲他們可能需要在組裝的其他地方使用它,它反正標記爲內部,即使他們不需要它的時候。另一位開發人員可能會考慮在那裏採取。通常情況下,你想標記爲私人,直到你有明確的需求。

但一些這可能是主觀的,我不是說應該永遠不會被使用。只需要時使用。

1

我曾經使用過的內部關鍵字的唯一事情是在我的產品;-)許可證檢查代碼

1

一個利用內部關鍵字是從您的程序集的限制用戶訪問的具體實現。

如果你有一個工廠或其他中心位置來構建對象,你的程序集的用戶只需要處理公共接口或抽象基類。

此外,內部構造函數允許您控制實例化其他公共類的位置和時間。

11

由於「儘可能使用嚴​​格修飾符」的規則,我使用內部任何地方我需要從另一個類訪問方法,直到我明確需要從另一個程序集訪問它。

由於程序集接口通常比其類接口的總和更窄,所以我使用它的地方相當多。

4

作爲原則進行的拇指有兩種成員組成:

  • 公共表面:從外部裝配可見(公共,保護,和內部保護): 呼叫者不被信任,因此參數驗證,方法文檔等是需要的。
  • 私人表面:從外部程序集(私有和內部類或內部類)不可見:調用者通常是可信的,因此可以省略參數驗證,方法文檔等。
4

減少噪音,你揭露的類型越少,你的圖書館就越簡單。 篡改打樣/安全是另一個(雖然反射可以贏得它)。

6

內部的一個非常有趣的用法 - 當然內部成員僅限於聲明它的程序集 - 在某種程度上獲得「朋友」功能。朋友成員是僅在其聲明的程序集外的某些其他程序集中可見的東西。 C#沒有內置的朋友支持,但是CLR的確支持。

您可以使用InternalsVisibleToAttribute申報的朋友集會,並從朋友組件內的所有引用將把您的聲明組件內的成員各界朋友集會的範圍之內。與此有關的一個問題是所有內部成員都可見;你不能挑選。

InternalsVisibleTo的一個很好的用法是將各種內部成員暴露給單元測試程序集,從而消除了對測試這些成員的複雜反射工作的需求。所有可見的內部成員都不是什麼大問題,但是採取這種方法會嚴重影響你的類接口,並且可能會破壞聲明程序集內的封裝。

2

我有一個項目,它使用LINQ到SQL的數據後端。我有兩個主要的命名空間:Biz和Data。LINQ數據模型存在於Data中並標記爲「internal」; Biz命名空間具有包裝LINQ數據類的公共類。

因此有Data.ClientBiz.Client;後者公開數據對象的所有相關屬性,如:

private Data.Client _client; 
public int Id { get { return _client.Id; } set { _client.Id = value; } } 

的商務對象有一個私有構造函數(強制使用的工廠方法),以及內部構造,看起來像這樣:

internal Client(Data.Client client) { 
    this._client = client; 
} 

這可以被庫中的任何業務類使用,但前端(UI)無法直接訪問數據模型,從而確保業務層始終充當中介。

這是我第一次真正使用internal很多,它證明非常有用。

7

有一天,也許一個星期,我記不起一個有趣的博客。基本上我不能讚揚這一點,但我認爲它可能有一些有用的應用程序。

假如你想讓一個抽象類被其他程序集看到,但你不想讓別人能夠繼承它。密封將不起作用,因爲它是抽象的原因,該組件中的其他類可以繼承它。 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(); 
    } 
    } 
} 

正如您所看到的,它有效地允許某人使用父類而不能繼承。

21

如果您正在編寫一個將大量複雜功能封裝到一個簡單的公共API中的DLL,那麼對於不會公開暴露的類成員使用「internal」。

隱藏複雜性(又名封裝)是高質量軟件工程的主要概念。

53

使用internal的另一個原因是如果您混淆了二進制文件。混淆器知道爭用任何內部類的類名是安全的,而公共類的名稱不能被混淆,因爲這會破壞現有的引用。

16

當您通過非託管代碼構建包裝時,內部關鍵字被大量使用。

當你有一個基於C/C++的庫,你想要DllImport你可以導入這些函數作爲一個類的靜態函數,並使他們內部,所以你的用戶只能訪問你的包裝,而不是原始的API它不能混淆任何東西。這些函數是靜態的,你可以在程序集中的任何地方使用它們,用於你需要的多個包裝類。

你可以看看Mono.Cairo,它是一個圍繞cairo庫的包裝器,它使用這種方法。

1

這個怎麼樣:通常建議您不要將List對象暴露給程序集的外部用戶,而是暴露IEnumerable。但是在程序集中使用List對象要容易得多,因爲你得到了數組語法和所有其他List方法。所以,我通常有一個內部屬性暴露了一個列表在程序集內部使用。

有關此方法的評論值得歡迎。

2

有一些情況是有意義的製作類internal成員。一個例子可能是如果你想控制這些類是如何實例化的;假設你提供某種工廠來創建類的實例。你可以使構造函數internal,以便工廠(駐留在相同的程序集中)可以創建該類的實例,但該程序集外部的代碼不能。

不過,我看不出任何一點與製造類或成員internal沒有具體原因,只是因爲小,因爲它是有道理的,使他們public,或private沒有具體原因。

1

請記住,定義爲public任何類將自動在智能感知顯示出來時,有人看你的項目的命名空間。從API的角度來看,只向項目的用戶顯示他們可以使用的類是很重要的。使用internal關鍵字隱藏他們不應該看到的內容。

如果您的項目A的Big_Important_Class打算用於您的項目之外,那麼您不應該標記它internal

然而,在許多項目中,你會經常有實際上只適用於一個項目中使用的類。例如,您可能有一個保存參數化線程調用參數的類。在這些情況下,如果沒有其他原因,您應將它們標記爲internal,而不是爲了保護您免於意外的API更改。

66

如果Bob需要BigImportantClass,那麼Bob需要讓擁有項目A的人員註冊以確保BigImportantClass將被寫入以滿足他的需求,經過測試以確保滿足他的需求,記錄爲滿足他的需求,並且將建立一個過程來確保它永遠不會被改變,從而不再滿足他的需求。

如果一個類的內部則不必經歷這個過程,這對於A計劃,他們可以在其他方面的支出節省預算。

內部的問題不在於它使生活困難的鮑勃。這就是它允許你控制項目A對特性,壽命,兼容性等方面的昂貴承諾。

0

的想法是,當你在設計一個圖書館只有達到預定可使用來自外部的類(通過庫的客戶端)應該是公開的。這樣,您就可以隱藏

  1. 有可能在未來的版本中更改類(如果他們是公衆,你會打破客戶端代碼)
  2. 沒用到客戶端,可能會引起混淆
  3. 並不安全(所以使用不當可能會破壞你的圖書館相當嚴重)

如果您正在開發解決方案,室內比使用內部元件不是那麼重要我猜,b因爲通常客戶會不斷與您聯繫和/或訪問代碼。不過,它們對於圖書館開發者來說相當重要

3

內部類使您能夠限制程序集的API。這有好處,比如讓你的API更易於理解。

此外,如果您的程序集中存在錯誤,修復程序引入重大更改的機會就會減少。沒有內部課程,你必須假設改變任何班級的公共成員將是一個突破性的變化。對於內部類,您可以假定修改其公共成員只會破壞程序集的內部API(以及InternalsVisibleTo屬性中引用的任何程序集)。

我喜歡在類級別和彙編級別進行封裝。有些人不同意這一點,但很高興知道該功能是可用的。

4

本示例包含兩個文件: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的可進入等級來公共。還要將成員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