我正在设计一个文本渲染器。我正在建立如何将字符串分成几行以适合文本框的逻辑。我要这样做的方法是,首先将完整的字符串分成“单词”,“空格”和“换行符”,然后构建一种算法来测量一行中可以容纳多少行,然后再移动到下一行。
但是,“ Word”必须是一个类/结构,因为它要保留“ FontStyle”,“ Colour”等额外属性。“ Space”和“ NewLine”只是标记-它们不需要任何数据。
目前,我有以下框架:
interface ILineComponent
{
}
struct Word : ILineComponent
{
public string Text;
public FontStyle Style;
public Colour Colour;
public Word(string text, FontStyle style, Colour colour)
{
Text = text;
Style = style;
Colour = colour;
}
}
struct Space : ILineComponent
{
}
struct NewLine : ILineComponent
{
}
struct Line
{
public List<ILineComponent> Segments;
public Line(List<ILineComponent> segments)
{
Segments = segments;
}
}
然后,我的想法是,我将遍历这条直线,并测量将一条线(或单词,...,换行符)拆分成另一行之前要容纳多少个(单词,空格,...,单词,空格)。目前,这将利用如下逻辑:
foreach (ILineComponent component in line)
{
if (component is Word)
//..
else if (component is Space)
//...
else if (component is NewLine)
//...
}
但是该设计违反了CA1040。
我该如何更好地设计?
空接口不仅违反了CA1040。它也违反了DRY的干净代码原则,因为很有可能在代码的多个位置使用这些if / else语句。如果不根据接口的存在做出一些决定,您将对空接口怎么办?
是的,让我们摆脱它。感谢您关心编译器警告并尝试编写更好的代码。
首先,我认为a的定义Space
不完整。没有字体也无法确定空间的宽度。因此,我认为空间应类似于Word
。也许它不需要颜色,当然也不需要文本作为参数。
struct Space : ILineComponent
{
public readonly string Text = " ";
public FontStyle Style;
public Word(FontStyle style)
{
Style = style;
}
}
我不认为这是的特殊情况Word
。稍后您会看到,为什么会这样。这是因为我提出接口的方式。
我也认为此代码具有误导性
foreach (ILineComponent component in line)
由于您还不知道多少行,因此该变量line
不正确。这应该是componentsOfText
或类似的。在循环内部,您将在需要时开始新行。
接下来,我建议您将这三个组件需要做的所有事情都放在界面中。据我了解,这是:
interface ILineComponent
{
int Measure();
bool IsTrimmedAtEndOfLine;
bool TerminatesLine;
}
对于NewLine
,Measure()
只需返回0。
您的代码如下所示:
// IList<LineComponent> is a line
// IList< -"- > are many lines
// Maybe you want to define an alias for that, or even a class
IList<IList<ILineComponent>> lines = new ...;
int remainingSpace = 2000; // px or whatever
while (componentsOfText.Length > 0)
{
component = componentsOfText[0];
var space = component.Measure();
if (space > remainingSpace)
{
// finish current line and start a new one,
// i.e. add a new List<LineComponent>,
// reset remaining space,
// do the line post processing (e.g. space width adjustment)
// Do not remove component from the list
continue;
}
if (component.TerminatesLine)
{
// Finish current line and start a new line
// just as before
}
remainingSpace -= space;
componentsOfText.Remove(component);
}
对于“完成当前行并开始新行”部分:
var lastitem = line[line.Count - 1];
if (lastitem.IsTrimmedAtEndOfLine)
{
line.Remove(lastitem);
}
// start the second pass for calculating the width of a space etc.
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句