如何防止具有公共派生类的抽象类在其他程序集中继承?

问题描述 投票:6回答:6

我想写如下内容:

    internal class InternalData
    {
    }

    public class PublicData
    {
    }

    abstract internal class Base {
        internal Base() { }

        private static InternalData CreateInternalDataFromPublicData(PublicData publicData)
        {
            throw new NotImplementedException();
        }

        abstract protected void DoProcess(InternalData internalData);

        public void Process(PublicData publicData)
        {
            InternalData internalData = CreateInternalDataFromPublicData(publicData);
            DoProcess(internalData);
        }
    }

    public sealed class Derived : Base
    {
        protected override void DoProcess(InternalData internalData)
        {
            throw new NotImplementedException();
        }
    }

也就是说,Base包含一些内部逻辑,不能由程序集外部的类继承;并且Derived可从外部访问。InternalData还包含一些内部逻辑,并且从不(从不应该从外部使用),我也想使其内部化。

当然,上面的代码不会编译,因为Base的访问权限不应比Derived少。我可以将Base设置为public,这很好,但这会导致另一个问题。如果Base是公开的,则其他某个程序集中可能会有ExternalDerived : Base。但是Base.DoProcess接受InternalData作为其参数,因此ExternalDerived无法实现它(因为它不知道InternalData)。内部无参数Base构造函数阻止创建任何ExternalDerived实例,因此没有人将实现ExternalDerived.DoProcess,并且不需要InternalData公共公开,但编译器不知道。

我该如何重写上面的代码,以便有一个抽象的DoProcess(InternalData)方法,并使InternalData类在内部?

c# inheritance public access-modifiers internal
6个回答
0
投票

Base设置为public

public abstract class Base {...

更改Base.DoProcess:

protected virtual void DoProcess<T>(T internalData)
{
    if (!(internalData is InternalData))
    {
        throw new ArgumentOutOfRangeException("internalData");
    }
}

Change Derived.DoProcess:

protected override void DoProcess<T>(T internalData)
{
    base.DoProcess(internalData);
    // Other operations
}

4
投票

要使InternalData为内部,DoProcess必须为privateinternal(或InternalAndProtected,但C#不支持此CLR功能)。不能是protectedprotected internal

internal abstract DoProcess(InternalData internalData);

我可能还会添加一个internal abstract void DoNotInheritFromThisClassInAnOutsideAssembly()成员。这样可以防止程序集外部的任何人从您的类继承,因为他们无法实现该成员,并且会遇到合理的编译器错误。但是您不能将Base类本身设置为内部。


我会考虑重构代码,以便您没有通用的基类。可能通过使用某些internal接口和组成。


1
投票

闻起来好像您应该使用composition instead of inheritance。抱歉,这是一个非常模糊的答案。我现在正在考虑更多。.


1
投票

基类型必须是可访问的,因为否则,将无法弄清基。您的Base直接来自System.Object,但是Derived的用户如何知道呢?它如何知道Base不是从另一个公共类型派生的,并且应该使该类型的成员可用?

如果您在Base内部标记了所有内容,除了类本身,则您已经阻止其他程序集对其进行任何有用的操作。换句话说,如果将DoProcess设为内部,则可以防止InternalData成为public

是的,如果其他类尝试调用DoProcess,则这会允许您自己的程序集中存在错误。不幸的是,没有“从同一程序集的派生类可访问”访问修饰符,只有“可从派生类访问”,“可从同一程序集访问”和“可从派生类访问且可从同一程序集访问”。 (实际上,.NET确实支持它,但是C#不支持。)


0
投票

自C#7.2起,存在private protected访问修饰符,这意味着“仅可用于同一程序集中的派生类”。]

换句话说,它必须同时满足internalprotected的条件,与protected internal适用于internalprotected的情况不同。

您可以将基类的构造函数标记为private protected,从而有效地防止通过此类构造函数在程序集外部继承该类,同时仍然允许该程序集(以及程序集的朋友)内的继承。

所以,这样的类:

public abstract BaseClass
{
    private protected BaseClass() {}
}

在程序集外部有效密封,但仍可在程序集内部继承。


-2
投票

实际上非常简单。您只需要派生类实现抽象的内部方法即可。库外部的类将无法实现abstract方法,因此在编译时会失败。

© www.soinside.com 2019 - 2024. All rights reserved.