如何不允许公开从特定类派生的类?

时间:2014-09-13 14:57:01

标签: c# .net sdk api-design

假设组件(比如CompA)在SDK中公开了一个公共C#.NET类(比如Base):

namespace CompA { public abstract class Base {} } 

另一个组件(比如ExtB)通过派生这个基类来扩展CompA:

namespace ExtB { class Derived : CompA.Base {} }

您有什么看法,不允许声明类ExtB.Derived为 public 的最佳方法是什么? CompA.Base用于扩展 CompA,但不用于使用它公开新的公共API。

namespace ExtB { public class Derived : CompA.Base {} } // DISALLOW

我能想到的是期望公开API的程序集用.NET自定义属性标记,并用另一个.NET自定义属性标记基类。加载这些程序集的产品将不允许加载这样的程序集,以暴露/发布从使用自定义属性标记的类型派生的类型。

CompA的AssemblyInfo.cs:

[assembly:SdkApiAssemblyAttribute()]

ExtB的AssemblyInfo.cs:

[assembly:SdkApiAssemblyAttribute()]

Base.cs:

namespace CompA
{
    [Publishable(false)]
    public abstract class Base {}
} 

谢谢!

2 个答案:

答案 0 :(得分:1)

首先,它听起来你做错了什么。在确认您的意图只是为了防止意外暴露类型之后,这听起来很合理。编写单元测试可能很简单,但如果派生类不是代码库的一部分,则可以执行以下操作。

没有编译时间方法来阻止这种情况(AFAIK)。只需检查Base类构造函数中的类型并抛出异常。

public abstract class Base
{
    protected Base()
    {
        if (this.GetType().IsPublic)
            throw new InvalidOperationException("Type is not meant to be exposed public");
    }
}

public class Der : Base
{
    public Der()
    {

    }
}

这将阻止客户端创建Der的新实例(如果它被声明为public

注意:有些情况下构造函数无法运行,那么你运气不好。幸运的是,他们是角落案件,不必担心太多。例如:FormatterServices.GetUninitializedObject不会运行构造函数。

答案 1 :(得分:0)

@SriramSakthivel,你是对的:我做错了什么! :)

虽然没有故意我没有说CompA.Base实际上不是一个类,而是一个接口

public interface Base
{
    string ShouldNotBePublic();
}

基类应该使用 protected 访问修饰符公开方法:

public abstract class Base
{
    protected string ShouldNotBePublic();
}

这样,派生类不会意外地暴露受保护的信息。然后,组件CompA可以通过实现模板方法模式来访问此方法:

namespace CompA
{
    public abstract class Base : IBaseInternal
    {
        protected string ShouldNotBePublic();

        string IBaseInternal.ShouldNotBePublic()
        {
            return ShouldNotBePublic();
        }
    }

    internal interface IBaseInternal
    {
        string ShouldNotBePublic();
    }
}

很抱歉这个混乱。