2015-07-13 142 views
1

這個問題可能有點奇怪。方案如下:阻止訪問繼承成員

  • 有一個稱爲對插件的接口IPlugin
  • 沒有爲插件稱爲PluginBase
  • 一個抽象基類(它實現接口)這些被存儲類庫
  • 內部

現在每個人都應該能夠通過創建一個新的類庫和一個派生自PluginBase的插件類來創建自己的插件。

PluginBase類將提供很多公共屬性,這些屬性用於從基本工具與插件接口進行通信。這是通過反思完成的;該工具將搜索基於接口IPlugin的類並創建該類的一個實例。

現在的問題是,這些公共屬性是必要的插件機制,但不應該從派生的插件類訪問或更改。簡而言之:用戶定義的插件類不應該能夠訪問其基類PluginBase的多個公共成員。

這可能不知?我知道我通常應該使用private作爲這些屬性(所以派生類無法訪問它們),但由於基類也充當插件接口,所以這是不可能的。

解決方案(基於Fabjan和Luaan的答案):

// basic plugin interface (IPlugin.dll) 
public interface IPlugin 
{ 
    // plugin communication interface 
    string SomeProperty { get; set; } 
    void SomeMethod(); 

    // public interface 
    string Name { get; } 
    void Run(); 
} 

// plugin base class (IPlugin.dll) 
public class PluginBase : IPlugin 
{ 
    string IPlugin.SomeProperty 
    { 
     get { return "Something"; } 
     set { /* ... */ } 
    } 

    void IPlugin.SomeMethod() 
    { 
     Console.WriteLine("Something"); 
    } 

    public string Name 
    { 
     get { return "MyName"; } 
    } 

    public void Run() 
    { 
     // ... 
    } 
} 

// user-defined plugin (MyPlugin.dll) 
public class MyPlugin : PluginBase 
{ 
    public MyPlugin() 
    { 
     // will not work 
     this.SomeProperty ... 
    } 
} 

// main assembly 
static void Main(string[] args) 
{ 
    Assembly asm = Assembly.LoadFrom(@"path\to\assembly"); 

    var type = asm.GetTypes().FirstOrDefault(t => t.GetInterface("NamespaceOfIPlugin.IPlugin", true) != null); 

    NamespaceOfIPlugin.IPlugin plugin = (NamespaceOfIPlugin.IPlugin)Activator.CreateInstance(type); 

    // works as expected 
    plugin.SomeMethod(); 
} 
+2

這聽起來對我來說,該信息不應該在該類。如果一個類擁有公共屬性,那麼它就不允許訪問,那麼它覺得這必須是關於該類的元數據,可能可能存儲在別處?你能否舉一個應該在班上但不在該班控制下的財產的例子?這可能有助於使問題和要求更易於理解。 – Chris

+0

這些公共屬性是從接口來的嗎? – gsharp

+0

@gsharp是的公共屬性來自「IPlugin」接口。正如我所說的,主程序集將加載插件程序集(DLL),該程序集包含一個用戶創建的插件類,它從'PluginBase'派生,因此實現'IPlugin'。主程序搜索這個類,創建一個實例,然後訪問一些公共屬性。主要組件只知道'IPlugin'。這些公共成員不應該被派生插件類訪問,因爲它們只能被主程序集用於插件通信。 –

回答

2

現在的問題是,這些公共屬性是必要的 插件機制,但不應該被訪問或從 導出插件類改變。

你試圖做的事情是不可能的,因爲如果類實現抽象類 - 它必須知道它的所有成員。你可以做的是,你可以做這樣的事情:

1)添加內部關鍵字爲你的界面

internal interface IPlugin 
{ 
    int MyProperty1 {get; set;} 
    int MyProperty2 {get; set;} 
    int MyProperty3 {get; set;} 
    void HiddenMethod(); 
} 

2)實現性能/要明確的隱藏方法:

abstract class PluginBase : IPlugin 
{ 
    public int MyProperty1 { get; set; } 
    public int MyProperty2 { get; set; } 
    int IPlugin.MyProperty3 { get; set; } 
    void IPlugin.HiddenMethod() {} 
} 

現在你可以在你的主要解決方案中使用你所有隱藏的方法和屬性,通過IPlugin接口輸入:

IPlugin instance = new MyConcretePlugin(); 

instance.MyProperty3 = 10; 
instance.HiddenMethod(); 

IPlugin接口現在不能從任何其他解決方案(除了擁有它的一個解決方案)訪問,因此對於所有隱藏成員也是如此。

+0

好吧我能夠用一些虛擬代碼來測試它,它完美地工作。它將「隱藏」派生類的屬性真的隱藏了它,但它在智能意義上是不可見的,或者通過簡單地使用'this.property'就可以改變。)因爲主程序集直接在'IPlugin'上工作,所以我甚至不需要改變訪問邏輯/代碼。這正是我想要的。 –

+0

在我的情況下,當我從另一個裝配中使用它時,接口將保持公共。 –

+0

@RobertS。不客氣 – Fabjan

1

你可以使用的方法和屬性只應該從組件中的internal

public class PluginBase : IPlugin 
{ 
    // Only accessible within the same assembly 
    internal static int x = 0; 
} 
+0

不完全是因爲你仍然可以使用反射訪問所有這些成員 – Fabjan

+0

我能夠訪問/更改來自另一個程序集反射的內部屬性? –

+0

是的,你可以使用反射訪問它們,但是你不能覆蓋和替換插件庫作爲內部的方法。你也可以看看密封的https://msdn.microsoft.com/en-us/library/88c54tsw.aspx – Thorarins

3

如果你不希望這些房產公開,也不要讓它們公開。

您的解決方案的體系結構看起來似乎不可靠。你期望(甚至要求甚至)所有插件實現PluginBase,但你搜索基於IPlugin接口的插件。爲什麼?挑一個,然後滾動。在框架中沒有規定必須基於某個接口來搜索插件。

要防止派生類訪問其父項的成員,請使用private訪問修飾符。如果你的插件管理器需要訪問這些值,你必須確保它實際上是這樣 - 例如,你可以讓負責處理這個數據的部分sealed嵌套類PluginBase

但最後,問題是 - 爲什麼?沒有必要嘗試派生類來避免訪問那些成員(爲什麼首先有這些成員?)。也許只有在明確實現的接口中具有這些屬性才足夠?這樣你仍然可以使用例如((IPluginBase)plugin).SomeProperty,但不是plugin.SomeProperty。這不像他們無法使用反射來獲取數據。

+0

PluginBase類基本上爲每個插件需要提供一些邏輯,因此不應該由每個插件實現。但對於該工具,「IPlugin」接口就足夠了。創建一個只能實現「IPlugin」而不是「PluginBase」的插件,但必須以某種方式實現「PluginBase」中的邏輯。這對於該工具也可以。 –

+0

我的目標不是阻止以任何方式訪問它們(例如通過反思),但它不應該很容易做到。實現自己的插件類的人只應該看到他應該允許更改的成員,而不是與插件通信的工具所使用的成員。插件界面有很多屬性是必需的,但對於插件開發者來說,只有極少數屬性是有用的。插件開發人員可以更改可能導致奇怪事情的值,但這種情況不應該發生(至少不能通過直接訪問某些成員以簡單的方式進行)。 –

+1

@RobertS。那麼,請使用顯式接口實現。保持字段爲'private',並且屬性是接口的顯式實現,並且派生類將不能直接訪問它們(它們需要做類似'((IPluginMetaData)這樣的事情).SomeMetaData'太難了,但也不太開放;無論如何,它聲明瞭訪問「隱藏」的意圖)。 – Luaan