如何利用List对象的多态性?

时间:2014-08-26 16:14:58

标签: c# list generics polymorphism

以下是我的以下问题的简要概述,以防我接近错误:

我有一个显示在datagrids中的客户,采购订单和发票清单。我想验证这些网格中显示的内容是否与我实际拥有的列表相匹配(这适用于自动化测试应用程序)。我试图处理它的方法是遍历每个表,并遍历每行对象,并将其与列表中的对象进行比较(因此是实际/预期的变量)。

我有一个包含多个List个对象的应用程序,例如:

List<PurchaseOrder>
List<Customer>
List<Invoice>

我希望能够编写一个可以操作每个列表的循环,而不是每个列表都有一个foreach语句。我有多个表显示每个对象(一个PO表,一个客户表等),我想迭代所有这些:

foreach(Table t in Tables)
{
    List<??> tableItems = new List<??>; // Perhaps this should be `object tableItems;`?

    switch(t.Name)
    {
        case "PurchaseOrder":
            tableItems = purchaseOrders; // purchaseOrders is a List<PurchaseOrder> object
            break;
        case "Customer":
            tableItems = customers; // List<Customer>
            break;
        case "Invoice":
            tableItems = invoices; // List<Invoice>
            break;
        default:
            break;
    }

    // Now I want to get the count of items, to loop through
    for(int i = 0; i < tableItems.Count; i++)
    {
        // Do work
    }
}

但是,我无法找到在这里使用多态的正确方法。如果我将tableItems设为对象列表(List<Object>),我将收到错误Cannot convert type of List<PurchaseOrder> to List<Object>

如果我将tableItems转换为Object类,我就无法调用.Count字段。

编辑:我知道我可以通过在每个case语句中放置for循环来轻松解决这个问题 -

case "PurchaseOrder":
    tableItems = purchaseOrders;
    for(int i = 0; i < tableItems.Count; i++)
    {
        // Do Work
    }
    break;

但是我想要一种方法来提取for循环。

编辑2 这是我现在使用的代码的另一个例子以及我想用它做什么,但不能完全弄清楚:

foreach(Table t in Tables)
    {
    List<??> tableItems = new List<??>; // Perhaps this should be `object tableItems;`?

    string expectedItem;
    string actualItem = t.rows[currentRow].Cells[column1].Value.ToString();

    switch(t.Name)
    {
        case "PurchaseOrder":
            for(int i = 0; i < purchaseOrders.Count; i++)
            {
                PurchaseOrder p = purchaseOrders[i];
                expectedItem = p.POValue1;
            }
            break;
        case "Customer":
            for(int i = 0; i < customers.Count; i++)
            {
                Customer c = customers[i];
                expectedItem = c.CustValue1;
            }
            break;
        case "Invoice":
            for(int i = 0; i < invoices.Count; i++)
            {
                Invoice inv = invoices[i];
                expectedItem = inv.InvoiceValue1;
            }
            break;
        default:
            break;
    }

    // I would prefer to do something like this:
    switch(t.Name)
    {
        case "PurchaseOrder":
            actualItem = purchaseOrders; // List<PurchaseOrder> object
            break;
        case "Customer":
            actualItem = customers; // List<Customer>
            break;
        case "Invoice":
            actualItem = invoices; // List<Invoice>
            break;
        default:
            break;
    }

    for(int i = 0; i < tableItems.Count; i++)
    {
        (object) o = tableItems[i];
        switch(object)
        {
            case "PurchaseOrder":
                expectedItem = o.POValue1;
                break;
            case "Customer":
                expectedItem = o.CustValue1;
                break;
            case "Invoice":
                expectedItem = inv.InvoiceValue1;
                break;
            default:
                break;
        }
    }
}

2 个答案:

答案 0 :(得分:2)

不是混合同时处理所有表的代码,而是一次解决一个表的问题。

每种对象类型都指示表格中显示的内容。这将始终是任何类型对象的元组。因此,如果验证方法获取这些显示对象而不是源代码就足够了:

//More or less pseudo code
bool Validate(Table table, object[][] displayObjects)
{
    for each iItem
        for each iColumn
            if(table.Rows[iItem].Columns[iColumn].Equals(displayObjects[iItem][iColumn])
                //everything is fine
            else
                //there is a validation error
}

这使我们完成了将任何对象列表转换为其各自的显示对象列表的任务。这可以使用LINQ:

执行
Validate(POTable, POList.Select(po => 
                new object[] { po.Property1, po.Property2, po.Property3 }).ToArray());
// ...

答案 1 :(得分:1)

OP。这似乎是一个XY问题。您的域名问题是您希望自动将DataSet与对象集合进行比较。您已注意到代码中存在共性,用于将PurchaseOrderPurchaseOrder表和InvoiceInvoice表进行比较。我建议您阅读设计模式,看看是否有适用于您的问题的模式。 战略模式看起来非常好......

public bool TableCollectionCompare<T>(
       Compare<DataRow, T> comparer, 
       DataTable table, 
       ICollection<T> objects);

另一种模式是abstract class来加载表和集合......

public abstract class TableCollectionComparer<T>
{
    protected bool Compare(DataRow row, T item);

    public bool Compare(DataTable table, ICollection<T> item)
    {
        foreach(DataRow row in table.Rows)
        {
             ...
             bool result = Compare(row, item);
        }
    }
}