[英]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
). 或者更确切地说,更具体地,对于每个绘制对象的接口实现此接口(
IWindow
是IDrawable
)。 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
). 仍然可以实现可重用的
ColorScheme
或IDrawable
(例如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.