阻止访问继承的成员

时间:2015-07-13 10:24:12

标签: c#

这个问题可能有点奇怪。方案如下:

  • 有一个名为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();
}

4 个答案:

答案 0 :(得分:3)

如果您不希望公开财产,请不要公开。

您的解决方案的体系结构似乎充其量也是不可靠的。您期望(要求偶数)所有插件实现PluginBase,但您会根据IPlugin接口搜索插件。为什么?选一个,然后滚动它。框架中没有规则必须根据某个界面搜索插件。

要防止派生类访问其父项的成员,请使用private访问修饰符。如果您的插件管理器需要访问这些值,您必须确保它确实存在 - 例如,您可以使负责处理此数据的部件成为sealed嵌套类PluginBase。< / p>

但最后,问题是 - 为什么?尝试强制派生类以避免访问这些成员(为什么首先有这些成员?),这一点没什么意义。也许将这些属性放在一个可以显式实现的接口中就足够了?这样你仍然可以使用例如((IPluginBase)plugin).SomeProperty,但不是plugin.SomeProperty。不管怎样他们都无法使用反射来获取数据。

答案 1 :(得分: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界面现在无法从任何其他解决方案访问(除了持有它的人),因此所有隐藏成员也是如此。

答案 2 :(得分:1)

您可以对仅应在程序集中提供的方法和属性使用internal

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

答案 3 :(得分:0)

您可以使用InternalsVisibleToAttribute。enter link description here