简体   繁体   English

强制类包含/使用自己的抽象类的特定实现

[英]Force classes to contain/use their own specific implementation of an abstract class

I'm developing a TUI library in C# and I need advice on how to do color themes for display objects. 我正在用C#开发一个TUI库,我需要有关如何为显示对象做颜色主题的建议。 Objects that can be drawn on the screen all inherit from this interface: 可以在屏幕上绘制的对象都从此接口继承:

public interface IDrawable
    {
        Area ScreenArea { get; }
        List<char[]> DisplayChars { get; }
        //some other properties...

    }

Or rather, more specifically, the interfaces for each drawable object implements this interface ( IWindow is a IDrawable ). 或者更确切地说,更具体地,对于每个绘制对象的接口实现此接口( IWindowIDrawable )。 Each IDrawable is drawn on a specified part of the console window represented by the Area struct: 每个IDrawable都绘制在由Area结构体表示的控制台窗口的指定部分上:

public struct Area
    {
        public readonly int EndX;
        public readonly int EndY;
        public readonly int Height;
        public readonly int StartX;
        public readonly int StartY;
        public readonly int Width;

        public Area(int startX, int endX, int startY, int endY)
        {
            StartX = startX;
            EndX = endX;
            StartY = startY;
            EndY = endY;
            Height = endY - startY;
            Width = endX - startX;
        }

        /// <summary>
        /// Get the overlapping area between this area and another.
        /// </summary>
        /// <param name="refArea"></param>
        /// <returns>Overlap area relative to the upper left corner of the ref area.</returns>
        public Area OverlapWith(Area refArea)
        {
            //....
        }
    }

The actual drawing of objects is handled by methods in a static Display class, which call Console.Write() on each element in DisplayChars. 对象的实际绘制由静态Display类中的方法处理,该类在DisplayChars中的每个元素上调用Console.Write() I would like for each class that inherits from IDrawable to be forced to implement its own rules for how its area can be divided into separate areas of color, for example, popup windows might have separate colorable areas for its outer borders, its title (within its outer border), and its inner area. 我希望从IDrawable继承的每个类被强制实现自己的规则,如何将其区域划分为单独的颜色区域,例如,弹出窗口可能具有用于其外边界的单独可着色区域,其标题(在它的外边界)和它的内部区域。

I've been tossing over how to do this in my head for a while now. 我一直在讨论如何做到这一点。 I need to make a type, ColorScheme , to contain the rules for what characters to write in what color. 我需要创建一个类型ColorScheme ,以包含用什么颜色写入哪些字符的规则。 I decided the best way to do this would be to make it an abstract class, which contains a list of "sub-areas" that colors can be applied to separately. 我决定最好的方法是将它作为一个抽象类,它包含一个“子区域”列表,颜色可以单独应用。

I'd like for each non-abstract IDrawable to have to implement its own class inheriting from ColorScheme . 我希望每个非抽象的IDrawable都必须实现自己继承自ColorScheme的类。 For instance, the abstract Window : IWindow class would have no such implementation, but PopupWindow : Window class would have to have a corresponding type of PopupWindowColorScheme : ColorScheme in which the author of PopupWindow would define how to split the class' Area into separate regions. 例如,抽象Window : IWindow类没有这样的实现,但是PopupWindow : Window类必须具有相应类型的PopupWindowColorScheme : ColorScheme ,其中PopupWindow的作者将定义如何将类' Area拆分为单独的区域。 Each PopupWindow would have its own instance of this type to contain its specific colors. 每个PopupWindow都有自己的这种类型的实例来包含它的特定颜色。

Is this possible? 这可能吗? If not, is there another way to force authors of IDrawable types to specify a method for splitting up their areas into colorable regions? 如果没有,是否有另一种方法可以强制IDrawable类型的作者指定将其区域分割为可着色区域的方法?

You can't force each IDrawable to have a unique implementation of ColorScheme (eg multiple different implementations of IDrawable could use PopupWindowColorScheme ). 你不能强迫每个IDrawable拥有的唯一实现ColorScheme (例如多个不同的实现IDrawable可以使用PopupWindowColorScheme )。 However, you can use generic type constraints to add additional requirements for implementing your interface, like this: 但是,您可以使用泛型类型约束来添加实现接口的其他要求,如下所示:

public interface IDrawable<TColorScheme> 
    where TColorScheme : ColorScheme
{
    Area ScreenArea { get; }
    List<char[]> DisplayChars { get; }
    //some other properties...
    TColorScheme ColorScheme { get; }
}

Now, every implementation of IDrawable needs to specify a type of ColorScheme to use. 现在, IDrawable每个实现IDrawable需要指定要使用的ColorScheme类型。 But a consumer could just implement IDrawable<ColorScheme> which sort of defeats the purpose (depending on your requirements). 但是,消费者可能只是实现IDrawable<ColorScheme> ,这种目的会失败(取决于您的要求)。 We can go a little further: 我们可以进一步:

public interface IDrawable<TColorScheme> 
    where TColorScheme : ColorScheme, new()
{
}

public abstract class ColorScheme {  }

Here, since ColorScheme is abstract, and the generic type constraint requires the provided type parameter to implement a parameterless constructor ( new() ), ColorScheme itself cannot be used as a parameter. 这里,由于ColorScheme是抽象的,并且泛型类型约束需要提供的类型参数来实现无参数构造函数( new() ),因此ColorScheme本身不能用作参数。 Any implementing class would need to specify a custom implementation of ColorScheme that provides a public, parameterless constructor. 任何实现类都需要指定ColorScheme的自定义实现,它提供一个公共的无参数构造函数。

But we can go even further: 但我们可以走得更远:

public interface IDrawable { } 
public interface IDrawable<TDrawable, TColorScheme> : IDrawable
    where TDrawable : IDrawable, new()
    where TColorScheme : ColorScheme<TDrawable>, new()
{
    object ScreenArea { get; }
    List<char[]> DisplayChars { get; }
    //some other properties...
    TColorScheme ColorScheme { get; }
}

public abstract class ColorScheme<TDrawable>
    where TDrawable : IDrawable, new()
{
}

Here, each implementation of IDrawable has to specify what ColorScheme it uses and each ColorScheme also has to specify what IDrawable it applies to. 在这里,每个实施IDrawable有指定什么ColorScheme它采用 ColorScheme也有指定什么IDrawable它适用于。 And because each requires a parameterless constructor, neither would be able to specify the common base type. 并且因为每个都需要无参数构造函数,所以它们都不能指定公共基类型。 Implementing this now looks a bit strange: 实现这一点现在看起来有点奇怪:

public class MyDrawable : IDrawable<MyDrawable, MyColorScheme> { }

public class MyColorScheme : ColorScheme<MyDrawable> { }

It's still possible to implement a reusable ColorScheme or IDrawable , (eg MyOtherDrawable : MyDrawable uses MyColorScheme ). 仍然可以实现可重用的ColorSchemeIDrawable (例如MyOtherDrawable : MyDrawable使用MyColorScheme )。 However, in my opinion, this is starting to get rather cumbersome and tedious to implement. 但是,在我看来,这开始变得相当繁琐和冗长。 In general, unless you have technical reasons why you have use a type constraint, I'd avoid using it, as you'll often find it too limiting in the future. 在一般情况下,除非你有技术的原因,你必须使用一个类型约束,我会避免使用它,因为你会经常发现它在未来的限制太多。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM