[英]How to prevent a class from being inherited outside the library, while being inherited by public classes?
[英]How to prevent an abstract class with public derived classes from being inherited in other assemblies?
我想寫如下內容:
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
類將是內部的?
要使InternalData
內部數據, DoProcess
必須是private
或internal
(或InternalAndProtected
,但 C# 不支持此 CLR 功能)。 它不能被protected
或protected internal
。
internal abstract DoProcess(InternalData internalData);
我可能還會添加一個internal abstract void DoNotInheritFromThisClassInAnOutsideAssembly()
成員。 這可以防止程序集之外的任何人從您的類繼承,因為他們無法實現該成員,並且會收到合理的編譯器錯誤。 但是您不能將Base
類本身設置為內部。
我會考慮重構代碼,這樣你就沒有通用的基類了。 可能通過使用一些internal
接口和組合。
由於 C# 7.2 有private protected
訪問修飾符,這意味着“僅可用於同一程序集中的派生類”。
換句話說,它必須同時滿足internal
AND protected
條件,這與適用於internal
OR protected
protected internal
不同。
您可以將基類的構造函數標記為private protected
,從而有效地防止在程序集外部通過此構造函數繼承該類,同時仍然允許在該程序集(以及程序集的朋友)內進行繼承。
所以,一個這樣的類:
public abstract BaseClass
{
private protected BaseClass() {}
}
在程序集之外被有效地密封,同時在程序集中仍然可以繼承。
聽起來你應該使用組合而不是繼承。 抱歉,這是一個非常模糊的答案。 我現在想的更多。。
基類型必須是可訪問的,否則就不可能找出它的基類型。 您的Base
直接從System.Object
派生,但Derived
的用戶如何知道這一點? 它怎么知道Base
不是從另一個公共類型派生的,並且該類型的成員應該可用?
如果您在Base
內部標記所有內容,除了類本身,您已經阻止了其他程序集對它做任何有用的事情。 換句話說,如果將DoProcess
內部,則可以防止InternalData
變為public
。
是的,誠然,如果其他類嘗試調用DoProcess
,這會導致您自己的程序DoProcess
。 不幸的是,沒有“可從同一程序集中的派生類訪問”訪問修飾符,只有“可從派生類訪問”、“可從同一程序集訪問”和“可從派生類訪問並從同一程序集訪問”。 (實際上,.NET 確實支持它,但 C# 不支持。)
將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
}
它實際上很簡單。 您只需要派生類實現抽象內部方法。 庫外的類將無法實現抽象方法,因此在編譯時會失敗。
您的示例已最小化為基本要素:
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();
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.