如何使用列表对象的多态性

本文关键字:多态性 对象 列表 何使用 | 更新日期: 2023-09-27 18:19:32

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

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

我有一个应用程序,它有多个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字段。

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

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

但我想要一种提取循环的方法。

编辑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;
        }
    }
}

如何使用列表对象的多态性

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

每种对象类型都规定了表中显示的内容。这将始终是任何类型的对象的元组。因此,如果验证方法得到这些显示对象而不是来源,那就足够了:

//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());
// ...

OP。这似乎是一个XY问题。您的域问题是,您希望自动比较DataSet与对象集合的集合。您已经注意到,在将PurchaseOrder s与PurchaseOrder表以及Invoice s与Invoice表进行比较的代码中存在共性。我建议你仔细阅读设计模式,看看是否有一种模式可以解决你的问题。战略模式看起来对它很好…

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);
        }
    }
}