NET开发人员。 决定使图层从数据源中提取一些数据,以进一步在某些生成的文档中构建表。
也许问题很简单,但我有点困惑。
问题是 - 想要构建可能包含字符串或图像的表模型。 目前我最终得到了这组课程,但我不确定这是否正确:
public class TableModel
{
public long RowsCount { get; set; }
public long ColumnsCount { get; set; }
public List<List<DataUnitModel>> Table { get; set; }
}
public class DataUnitModel
{
public object Element { get; set; }
public Type ElementType { get; set; }
}
它假设是这样的(伪代码):
public void BuildTable(TableModel myTable)
{
for (var i = 0; i < myTable.Rows)
{
for (var j = 0; j < myTable.Cols)
{
DocumentCurrentRange.Insert(myTable.Table[i][j]);
}
}
}
UPD:
数据类型 - 它可以是jsut简单字符串或jpg / png / bmp图像
UPD2:
Txnks家伙,意识到我不需要GetElement
功能,这里没用。
答案 0 :(得分:1)
您的扩展程序DataUnitModelExtensions.GetElement
唯一能做的就是确保DataUnitModel.Element
中包含的数据是Image
,string
或null
。从您的问题来看,这是此属性可以包含的唯一数据类型。所以你的扩展方法基本上没有用。你在那里使用了两个as
强制转换,非常适合类型转换,但是你返回一个object
,这使得你的类型转换没用。
如果要公开Element
字段的内容,请使用返回Image
和string
的两个不同属性。由于您自己定义DataUnitModel
类,因此不需要扩展方法:
public class DataUnitModel
{
public object Element { get; set; }
public string ElementText { get { return Element as string; } }
public Image ElementImage { get { return Element as Image; } }
public Type ElementType { get; set; }
}
如果您想获取元素类型,可以使用GetType
作为ElementType
属性,尽管一些简单的bool
属性可以完成此任务:
public class DataUnitModel
{
public object Element { get; set; }
public string ElementText { get { return Element as string; } }
public Image ElementImage { get { return Element as Image; } }
public Type ElementType { get { Element != null ? Element.GetType() : null; }
public bool IsElementText { get { return Element is string; } }
public bool IsElementImage { get { return Element is Image; } }
}
答案 1 :(得分:1)
您可以使用界面:
public interface IDataUnitModel{}
public class StringDataUnitModel : IDataUnitModel
{
public string Value {get;set;}
}
public class ImageDataUnitModel : IDataUnitModel
{
public Image Value {get;set;}
}
//...
public List<IDataUnitModel> list = new List<IDataUnitModel>();
list.Add(new StringDataUnitModel{Value = "ABC"});
list.Add(new ImageDataUnitModel());
在检索时,您可以检查对象的类型。你也只能放入图像&amp;字符串。
如果表格只能包含图片或字符串,则可以使用泛型。
答案 2 :(得分:1)
看来你在这里采取了一种稍微错误的做法,即你正在解决错误的问题。你的“表格”可能只是一个List<List<object>>
,它基本上会带有你班上现在携带的相同信息(除了“列数”,如果列表为空)。
如果我理解了您的问题,每种元素类型将以某种方式“呈现”(作为报告,或在网页中,或转换为其他内容)。如果这是真的,我将集中精力定义所有元素的渲染步骤的共同点。因此,最终结果应该允许您编写类似的内容:
var html = new StringBuilder();
foreach (var item in document.Items)
{
// get the renderer for this item type
var renderer = renderers[item.GetType()];
// append to the report
renderer.Append(html, item);
}
简化的报告模型可以是段落,表格,图形的列表,例如:
<Document>
<Paragraph>
Some text
</Paragraph>
<Table>
<HeaderRow>
<Col>Num</Col> <Col>Name</Col> ...
<HeaderRow>
<Row>
<Col>Num</Col> <Col>Name</Col> ...
<Row>
</Table>
<Image Url="..." />
</Document>
或许每个元素也都有一个子元素列表,但这是一个简单的例子。
然后您的模型将用以下内容表达:
interface IDocument
{
List<IItem> Items { get; }
}
interface IItem
{
// common properties which apply to all items
// (if they don't apply to all items, they
// shouldn't be here)
bool CanBreakAcrossPages { get; }
}
interface ITextualItem : IItem
{
string TextFont { get; }
float TextSize { get; }
...
}
class ParagraphItem : ITextualItem
{
public bool CanBreakAcrossPages { get; set; }
public string TextFont { get; set; }
public float TextSize { get; set; }
string Text { get; set; }
}
... you get the idea
然后,独立地,你可能有这样的渲染器界面:
// there are several ways to do this, but this is
// just a simple way to avoid casting all over the
// code, and still have generics for better type safety
interface IHtmlRenderer
{
void Append(StringBuilder html, object element);
}
interface IHtmlRenderer<T> : IHtmlRenderer where T : IItem
{
void Append(StringBuilder html, T element);
}
abstract class BaseHtmlRenderer<T> : IHtmlRenderer<T> where T : IItem
{
public void Append(StringBuilder html, object element)
{
// this is the only place where we will cast
this.Append(html, (T)element);
}
abstract public void Append(StringBuilder html, T element);
}
这使得创建不同的渲染器变得明显:
class ParagraphRenderer : BaseHtmlRenderer<ParagraphItem>
{
public override void Append(StringBuilder html, ParagraphItem element)
{
// do stuff
}
}
class ImageRenderer : BaseHtmlRenderer<ImageItem>
{
public override void Append(StringBuilder html, ImageItem element)
{
// do stuff
}
}
您要做的就是为每个IItem
类型(项目类型 - &gt;渲染器)创建映射渲染器。这甚至可以通过反射/依赖注入来完成,这样当你决定创建一个新的渲染器类型时,一切都会“正常工作”:
// this can easily be done automatically through reflection
var renderers = new Dictionary<Type, Action<StringBuilder, object>>();
renderers[typeof(ImageItem)] = new ParagraphRenderer().Append;
renderers[typeof(ParagraphItem)] = new ParagraphRenderer().Append;
现在我们达到了我们想要的用途:
var html = new StringBuilder();
foreach (var item in document.Items)
{
// get the renderer for this item type
var renderer = renderers[item.GetType()];
// append to the report
renderer.Append(html, item);
}
这会将您带到表格项目,这些表项目在您的案例中很有趣,因为它们显然可以包含图像和段落作为表格单元格。这意味着您可以将它们定义为:
class TableItem : ITextualItem
{
// note the recursion here:
// ITableItem is an IItem, and it contains a list of IItems,
// meaning you can even have nested tables inside a single table cell
public List<IItem> HeaderCols { get; }
public List<List<IItem>> Rows { get; }
}
然后渲染器再次有趣,因为它是一个复合(递归)渲染器:
public class TableRenderer : BaseHtmlRenderer<TableItem>
{
// we need to be able to render individual cells
private Dictionary<Type, Action<StringBuilder, object>> _renderers;
public override void Append(StringBuilder html, TableItem element)
{
RenderHeaderRowStart(html);
foreach (var col in element.HeaderCols)
{
var cellRenderer = _renderers[col.GetType()];
cellRenderer.Append(html);
}
RenderHeaderRowEnd(html);
...
}
}
这意味着您需要将字典传递给渲染器构造函数:
// renderers dictionary contains a TableRenderer, which also keeps
// a reference to this same dictionary
renderers[typeof(TableItem)] = new TableRenderer(renderers).Append;