2015-07-13 61 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