【问题标题】:How can I utilize Polymorphism with List objects?如何将多态性与 List 对象结合使用?
【发布时间】:2014-08-26 16:14:57
【问题描述】:

以下是我的以下问题的简要概述,以防我处理不正确:

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

我有一个包含多个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&lt;Object&gt;),我将收到错误 Cannot convert type of List&lt;PurchaseOrder&gt; to List&lt;Object&gt;

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

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

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

【问题讨论】:

  • 您的PurchaseOrderCustomerInvoice 类有接口还是基类?
  • 不,他们之间真的没有任何共同之处。我想我可以添加一个,但对于我实际上要保存的几行代码来说,这不值得。
  • 我的印象是你混淆了多态性和泛型?两者都熟悉吗?另外开头的table类型是什么?
  • 你对这些物品做了什么样的工作?
  • 请将多态性改为泛型

标签: c# list generics polymorphism


【解决方案1】:

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

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

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

【讨论】:

  • 非常感谢您在这方面的帮助,我已经弄清楚了!
【解决方案2】:

操作。这似乎是一个 XY 问题。您的域问题是您希望自动将DataSet 与对象集合的集合进行比较。您已经注意到将PurchaseOrders 与PurchaseOrder 表和Invoices 与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);
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-25
    • 2021-06-25
    • 2021-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多