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

发布于 2025-01-08 03:55:48 字数 1580 浏览 0 评论 0原文

我想编写如下内容:

    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 无法实现它(因为它不知道 内部数据)。 内部无参数 Base 构造函数会阻止创建任何 ExternalDerived 实例,因此没有人会实现 ExternalDerived.DoProcess 并且没有 InternalData需要公开曝光,但编译器不知道。

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

I want to write something like the following:

    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();
        }
    }

That is, Base contains some internal logic and is not intended to be inherited by classes outside of my assembly; and Derived is accessible from the outside.
InternalData also contains some internal logic and, as it would (and should) never be used from the outside, i also want to make it internal.

Of course the code above won't compile as the Base should not be less accessible than Derived. I can set the Base to be public, that's fine, but it leads to another problem.
If Base is public, then there could possibly be some ExternalDerived : Base in some other assembly. But Base.DoProcess accepts an InternalData as its argument, so that ExternalDerived cannot implement it (as it doesn't know about the InternalData).
Internal parameterless Base constructor prevents creation of any ExternalDerived instances, and thus nobody will implement ExternalDerived.DoProcess and no InternalData public exposure is needed, but the compiler doesn't know it.

How can i rewrite the code above so that there will be an abstract DoProcess(InternalData) method and so that InternalData class will be internal?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

凌乱心跳 2025-01-15 03:55:48

从 C# 7.2 开始,就有了 private protected 访问修饰符,这意味着“仅适用于同一程序集中的派生类”。

换句话说,它必须满足 internalprotected 的条件,这与适用于 internal OR 的 protected internal 不同受保护

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

因此,像这样的类:

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

有效地密封在程序集外部,同时仍然可以在程序集内继承。

Since C# 7.2 there is private protected access modifier, which means "available only to derived classes in the same assembly".

In other words, it must meet conditions for both internal AND protected, unlike protected internal which applies to internal OR protected.

You can mark the base class' constructor as private protected, effectively preventing inheritance of that class through this constructor outside the assembly while still allowing inheritance within that assembly (and the assembly's friends).

So, a class like this:

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

is effectively sealed outside the assembly, while still inheritable within the assembly.

梦行七里 2025-01-15 03:55:48

要使 InternalData 成为内部数据,DoProcess 必须是 privateinternal
(或 InternalAndProtected,但 C# 不支持此 CLR 功能)。它不能受保护内部保护

internal abstract DoProcess(InternalData internalData);

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


我会考虑重构代码,这样就没有公共基类了。可能是通过使用一些内部接口和组合。

To make InternalData internal, DoProcess must be private or internal
(or InternalAndProtected, but C# doesn't support this CLR feature). It can't be protected or protected internal.

internal abstract DoProcess(InternalData internalData);

I'd probably also add an internal abstract void DoNotInheritFromThisClassInAnOutsideAssembly() member. That prevents anybody outside the assembly from inheriting from your class, because they can't implement that member and they get a reasonable compiler error. But you can't make the Base class itself internal.


I'd consider refactoring the code, so that you have no common base class. Probably by using some internal interfaces and composition.

忆梦 2025-01-15 03:55:48

闻起来你应该使用 组合而不是继承。抱歉,这是一个非常模糊的答案。我现在更多地考虑这个问题..

It smells like you should use composition instead of inheritance. sorry, this is a very vague answer. I'm thinking more about this now..

优雅的叶子 2025-01-15 03:55:48

基类型必须是可访问的,否则就不可能找出它的基类型。您的 Base 直接派生自 System.Object,但是 Derived 的用户如何知道这一点呢?它如何知道 Base 不是从另一个公共类型派生的,并且该类型的成员应该可用?

如果将 Base 中的所有内容标记为内部(类本身除外),那么您就已经阻止了其他程序集使用它执行任何有用的操作。换句话说,如果将 DoProcess 设为内部,则可以防止 InternalData 变为 public

是的,无可否认,如果其他类尝试调用 DoProcess,那么您自己的程序集中可能会出现错误。不幸的是,没有“可从同一程序集中的派生类访问”访问修饰符,只有“可从派生类访问”、“可从同一程序集访问”和“可从派生类访问并可从同一程序集访问”。 (实际上,.NET 确实支持它,但 C# 不支持。)

The base type must be accessible, because otherwise, it becomes impossible to figure out its base. Your Base derives directly from System.Object, but how does a user of Derived know that? How does it know that Base doesn't derive from another public type, and that type's members should be made available?

If you mark everything in Base internal, except for the class itself, you've already prevented other assemblies from doing anything useful with it. In other words, if you make DoProcess internal, you can then prevent InternalData from becoming public.

Yes, admittedly this allows for bugs in your own assembly, if other classes try to call DoProcess. Unfortunately, there is no "accessible from derived classes in the same assembly" access modifier, only "accessible from derived classes", "accessible from the same assembly" and "accessible from derived classes and accessible from the same assembly". (Actually, .NET does support it, but C# doesn't.)

中性美 2025-01-15 03:55:48

Base设置为public

public abstract class Base {...

更改Base.DoProcess:

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

更改Derived.DoProcess: >

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

Set Base to be public.

public abstract class Base {...

Change 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
}
最舍不得你 2025-01-15 03:55:48

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

您的示例已最小化,仅包含必需品:

abstract internal class Base {
    internal protected abstract void DoProcess();

    public void Process() {
        DoProcess();
    }
}

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

It is actually quite straight forward. You just require that a deriving class implement an abstract internal method. Classes outside the library won't be able to implement the abstract method, and thus fail at compile time.

Your example, minimized to just the essentials:

abstract internal class Base {
    internal protected abstract void DoProcess();

    public void Process() {
        DoProcess();
    }
}

public sealed class Derived : Base {
    internal protected override void DoProcess() {
        throw new NotImplementedException();
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文