1

我正在用 C# 开发一个 TUI 库,我需要有关如何为显示对象制作颜色主题的建议。可以在屏幕上绘制的对象都继承自这个接口:

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

    }

或者更确切地说,每个可绘制对象的接口都实现了这个接口(IWindowis a IDrawable)。每个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)
        {
            //....
        }
    }

对象的实际绘制由静态Display类中的方法处理,这些方法调用Console.Write()DisplayChars 中的每个元素。我希望每个继承自IDrawable的类都被迫实施其自己的规则,以将其区域划分为不同的颜色区域,例如,弹出窗口可能有单独的可着色区域用于其外边框、其标题(在其内部外边界)及其内部区域。

一段时间以来,我一直在思考如何做到这一点。我需要创建一个类型 ,ColorScheme来包含用什么颜色写什么字符的规则。我决定最好的方法是让它成为一个抽象类,其中包含一个“子区域”列表,颜色可以单独应用。

我希望每个非抽象IDrawable都必须实现自己的继承自ColorScheme. 例如,抽象Window : IWindow类将没有这样的实现,但PopupWindow : Window类必须具有相应的类型,PopupWindowColorScheme : ColorScheme其中的作者PopupWindow将定义如何将类拆分Area为单独的区域。每个PopupWindow都有自己的这种类型的实例来包含其特定的颜色。

这可能吗?如果没有,是否有另一种方法可以强制IDrawable类型作者指定将其区域划分为可着色区域的方法?

4

1 回答 1

0

您不能强迫每个IDrawable人都有一个独特的实现(例如,可以使用ColorScheme的多个不同实现)。但是,您可以使用泛型类型约束来添加实现接口的额外要求,如下所示:IDrawablePopupWindowColorScheme

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所以本身不能作为参数。任何实现类都需要指定ColorScheme提供公共、无参数构造函数的自定义实现。

但我们可以走得更远:

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> { }

仍然可以实现可重用的ColorSchemeIDrawable,(例如MyOtherDrawable : MyDrawable使用MyColorScheme)。但是,在我看来,这开始变得相当繁琐和乏味。一般来说,除非您出于技术原因使用类型约束,否则我会避免使用它,因为将来您经常会发现它过于局限。

于 2016-05-08T01:52:03.583 回答