强制 classes 到 contain/use 他们自己的抽象具体实现 class
Force classes to contain/use their own specific implementation of an abstract class
我正在用 C# 开发一个 TUI 库,我需要有关如何为显示 object 制作颜色主题的建议。 Objects可以在屏幕上绘制的都继承自这个接口:
public interface IDrawable
{
Area ScreenArea { get; }
List<char[]> DisplayChars { get; }
//some other properties...
}
或者更具体地说,每个可绘制对象的接口 object 实现了这个接口(IWindow
是一个 IDrawable
)。每个 IDrawable
都绘制在由 Area 结构表示的控制台 window 的指定部分:
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)
{
//....
}
}
objects 的实际绘制由静态 Display
class 中的方法处理,这些方法在 DisplayChars 中的每个元素上调用 Console.Write()
。我希望每个从 IDrawable
继承的 class 都被迫实施自己的规则,以将其区域划分为不同的颜色区域,例如,弹出窗口 windows 可能有为其外边框、标题(在外边框内)和内部区域单独着色。
一段时间以来,我一直在思考如何做到这一点。我需要创建一个类型 ColorScheme
,以包含用什么颜色书写什么字符的规则。我决定最好的方法是将其设为抽象 class,其中包含可以单独应用颜色的 "sub-areas" 列表。
我希望每个 non-abstract IDrawable
都必须实现自己的 class 继承自 ColorScheme
。例如,抽象 Window : IWindow
class 将没有这样的实现,但 PopupWindow : Window
class 必须具有相应的 PopupWindowColorScheme : ColorScheme
类型,其中作者PopupWindow
将定义如何将 class' Area
拆分为单独的区域。每个 PopupWindow
都有自己的这种类型的实例来包含其特定的颜色。
这可能吗?如果不是,是否有另一种方法可以强制 IDrawable
类型的作者指定一种将其区域拆分为可着色区域的方法?
您不能强制每个 IDrawable
都具有 唯一的 ColorScheme
实现(例如 IDrawable
的多个不同实现可以使用PopupWindowColorScheme
)。但是,您可以使用 generic type constraints 添加实现接口的额外要求,如下所示:
public interface IDrawable<TColorScheme>
where TColorScheme : ColorScheme
{
Area ScreenArea { get; }
List<char[]> DisplayChars { get; }
//some other properties...
TColorScheme ColorScheme { get; }
}
现在,IDrawable
的每个实现都需要指定要使用的 ColorScheme
类型。但是消费者可以只实施 IDrawable<ColorScheme>
哪种方式违背了目的(取决于您的要求)。我们可以更进一步:
public interface IDrawable<TColorScheme>
where TColorScheme : ColorScheme, new()
{
}
public abstract class ColorScheme { }
这里,由于ColorScheme
是抽象的,泛型类型约束需要提供的类型参数来实现一个无参构造器(new()
),所以ColorScheme
本身不能作为范围。任何实现 class 都需要指定 ColorScheme
的自定义实现,它提供 public、无参数构造函数。
但我们可以走得更远:
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()
{
}
在这里,IDrawable
的每个实现都必须指定 ColorScheme
它使用什么 和 每个 ColorScheme
还必须指定 IDrawable
它适用于什么。而且因为每个都需要一个无参数的构造函数,所以它们都不能指定公共基类型。现在实现这个看起来有点奇怪:
public class MyDrawable : IDrawable<MyDrawable, MyColorScheme> { }
public class MyColorScheme : ColorScheme<MyDrawable> { }
仍然可以实现可重复使用的 ColorScheme
或 IDrawable
,(例如 MyOtherDrawable : MyDrawable
使用 MyColorScheme
)。然而,在我看来,这开始变得相当繁琐和乏味。一般来说,除非你有技术原因 使用类型约束,否则我会避免使用它,因为你经常会发现它在未来太受限制了。
我正在用 C# 开发一个 TUI 库,我需要有关如何为显示 object 制作颜色主题的建议。 Objects可以在屏幕上绘制的都继承自这个接口:
public interface IDrawable
{
Area ScreenArea { get; }
List<char[]> DisplayChars { get; }
//some other properties...
}
或者更具体地说,每个可绘制对象的接口 object 实现了这个接口(IWindow
是一个 IDrawable
)。每个 IDrawable
都绘制在由 Area 结构表示的控制台 window 的指定部分:
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)
{
//....
}
}
objects 的实际绘制由静态 Display
class 中的方法处理,这些方法在 DisplayChars 中的每个元素上调用 Console.Write()
。我希望每个从 IDrawable
继承的 class 都被迫实施自己的规则,以将其区域划分为不同的颜色区域,例如,弹出窗口 windows 可能有为其外边框、标题(在外边框内)和内部区域单独着色。
一段时间以来,我一直在思考如何做到这一点。我需要创建一个类型 ColorScheme
,以包含用什么颜色书写什么字符的规则。我决定最好的方法是将其设为抽象 class,其中包含可以单独应用颜色的 "sub-areas" 列表。
我希望每个 non-abstract IDrawable
都必须实现自己的 class 继承自 ColorScheme
。例如,抽象 Window : IWindow
class 将没有这样的实现,但 PopupWindow : Window
class 必须具有相应的 PopupWindowColorScheme : ColorScheme
类型,其中作者PopupWindow
将定义如何将 class' Area
拆分为单独的区域。每个 PopupWindow
都有自己的这种类型的实例来包含其特定的颜色。
这可能吗?如果不是,是否有另一种方法可以强制 IDrawable
类型的作者指定一种将其区域拆分为可着色区域的方法?
您不能强制每个 IDrawable
都具有 唯一的 ColorScheme
实现(例如 IDrawable
的多个不同实现可以使用PopupWindowColorScheme
)。但是,您可以使用 generic type constraints 添加实现接口的额外要求,如下所示:
public interface IDrawable<TColorScheme>
where TColorScheme : ColorScheme
{
Area ScreenArea { get; }
List<char[]> DisplayChars { get; }
//some other properties...
TColorScheme ColorScheme { get; }
}
现在,IDrawable
的每个实现都需要指定要使用的 ColorScheme
类型。但是消费者可以只实施 IDrawable<ColorScheme>
哪种方式违背了目的(取决于您的要求)。我们可以更进一步:
public interface IDrawable<TColorScheme>
where TColorScheme : ColorScheme, new()
{
}
public abstract class ColorScheme { }
这里,由于ColorScheme
是抽象的,泛型类型约束需要提供的类型参数来实现一个无参构造器(new()
),所以ColorScheme
本身不能作为范围。任何实现 class 都需要指定 ColorScheme
的自定义实现,它提供 public、无参数构造函数。
但我们可以走得更远:
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()
{
}
在这里,IDrawable
的每个实现都必须指定 ColorScheme
它使用什么 和 每个 ColorScheme
还必须指定 IDrawable
它适用于什么。而且因为每个都需要一个无参数的构造函数,所以它们都不能指定公共基类型。现在实现这个看起来有点奇怪:
public class MyDrawable : IDrawable<MyDrawable, MyColorScheme> { }
public class MyColorScheme : ColorScheme<MyDrawable> { }
仍然可以实现可重复使用的 ColorScheme
或 IDrawable
,(例如 MyOtherDrawable : MyDrawable
使用 MyColorScheme
)。然而,在我看来,这开始变得相当繁琐和乏味。一般来说,除非你有技术原因 使用类型约束,否则我会避免使用它,因为你经常会发现它在未来太受限制了。