是否可以将基数 class 限制为特定子 class?

Is it possible to restrict a base class to a specific subclass?

我有一个需要,我希望有一个基地 class 只对一个特定的子 class 可用。这是由于无法将 Attribute 定义为泛型的内部 class 的限制。

我们想要在泛型中定义属性的原因是当您这样做并将其类型设置为 protected 时,该属性现在仅可用于您的基础 classes class,保持您的 API 清洁。

例如,考虑继承自 MarkupExtension 的抽象 class ExampleMarkupExtension<T>。我想将属性 StaticInfoAttribute 定义为内部 class,因此它仅适用于 ExampleMarkupExtension<T>.

的子class

但是,如前所述,您不能将属性定义为泛型的内部 class,因此我的解决方法是创建第二个非泛型 ExampleMarkupExtensionBase class 继承自 MarkupExtension,将 StaticInfoAttribute 定义为内部 class,然后让泛型继承自 class。

现在的问题是我的层次结构中有一个额外的 class,任何人都可以子class。虽然它在技术上是无害的,但我喜欢保持我的 API 表面积清洁。

例子

ExampleMarkupExtensionBase : 非通用抽象基础 class

这是定义属性的 class,该属性应该仅供此 class 的子class使用。这个 class 之所以存在,是因为我不能将 StaticInfoAttribute 放在下面的通用抽象基础 class ExampleMarkupExtension<T> 中。

public abstract class ExampleMarkupExtensionBase : MarkupExtension {

    [AttributeUsage(AttributeTargets.Class, AllowMultiple=false, Inherited=false)]
    protected class StaticInfoAttribute : Attribute {
        public StaticInfoAttribute(string value) => Value = value;
        public readonly string Value;
    }
}

ExampleMarkupExtension<T> : 通用抽象基础 class

这是 class,它包含此 class 的子 class 所独有的静态成员。它通过使用 subclass 作为基础 class 的类型参数来实现这一点(参见 where 子句)。静态字段的值是根据属性设置的,因此它仅对上面 ExampleMarkupExtension 的这个特定子 class 有用。

public abstract class ExampleMarkupExtension<T> : ExampleMarkupExtensionBase
where T : ExampleMarkupExtension<T> {

    static ExampleMarkupExtension() => Value = typeof(T).GetRequiredCustomAttribute<StaticInfoAttribute>().Value;

    public static readonly string Value;

    public sealed override object ProvideValue(IServiceProvider serviceProvider)
        => Value;
}

理由

有些人可能会问保持原样有什么坏处。从技术上讲,让一个人subclassExampleMarkupExtensionBase并没有错。只是没有意义。

就此而言,从技术上讲,将 StaticInfoAttribute 移到 class 之外也没有任何危害,完全消除了对非通用基 class 的需要。我只是选择了前一种方法,因为限制属性的使用比阻止某人从 subclassing 基础 class.

更重要

根据我们的评论,您可以使用 EditorBrowsable 属性从引用它的项目中隐藏该方法。但是请注意,它只是对 IntelliSense 隐藏了它,如果用户输入 ExampleMarkupExtensionBase,则 class 仍然存在并且可以使用。

[EditorBrowsable(EditorBrowsableState.Never)]
public abstract class ExampleMarkupExtensionBase : MarkupExtension