【问题标题】:Passing and processing List<> types containing objects of the same base type传递和处理包含相同基类型对象的 List<> 类型
【发布时间】:2009-06-04 13:52:10
【问题描述】:

考虑以下类:

class TypeA;
class TypeB : TypeA;
class TypeC : TypeA;
class TypeD : TypeA;

和以下 List 类型:

List<TypeB> listTypeB;
List<TypeC> listTypeC;
List<TypeD> listTypeD;

现在 TypeA 有一个 Object1 类型的属性 Prop1,我想找到哪个列表中存储了一个具有给定值 Prop1 的项目。有没有一种方法可以让我执行以下操作,这样我只需要编写一次搜索代码?

bool LocateInAnyList(Object1 findObj)
{
  bool found = false;

  found = ContainsProp1(findObj, listTypeB);
  if(!found)
  {
    found = ContainsProp1(findObj, listTypeC);
  }
  if(!found)
  {
    found = ContainsProp1(findObj, listTypeD);
  }
  return found;
}


bool ContainsProp1(Object1 searchFor, List<TypeA> listToSearch)
{
   bool found = false;

   for(int i = 0; (i < listToSearch.Count) & !found; i++)
   {
      found = listToSearch[i].Prop1 == searchFor;
   }
   return found;
}

【问题讨论】:

    标签: c# inheritance collections


    【解决方案1】:

    是的。您需要使用约束使“包含”方法成为通用方法,以便您只能对派生自 TypeA 的对象进行操作(因此具有 Prop1:)

    bool ContainsProp1<T>(Object1 searchFor, List<T> listToSearch) where T : TypeA
    {
       bool found = false;
    
       for(int i = 0; (i < listToSearch.Count) & !found; i++)
       {
          found = listToSearch[i].Prop1 == searchFor;
       }
       return found;
    }
    

    您的第一个方法应该按原样编译。

    【讨论】:

    • 你确定这样编译吗?
    • 我删除了多余的冒号;除此之外,是的,我觉得很好。
    • 关闭 - 不幸的是,ybo 语法对于函数定义是正确的,但无论如何都要 +1。
    • 当我按原样粘贴该代码时,IDE 会突出显示“where”关键字并出现以下错误:“非泛型声明上不允许使用约束”要修复它,我必须将其更改为: bool ContainsProp1(Object1 searchFor, List listToSearch) where T : TypeA {...}
    【解决方案2】:

    你可以使用泛型

    bool ContainsProp1<T>(Object1 searchFor, List<T> listToSearch) where T : TypeA
    {
       bool found = false;
    
       for(int i = 0; (i < listToSearch.Count) & !found; i++)
       {
          found = listToSearch[i].Prop1 == searchFor;
       }
       return found;
    }
    

    如果你会使用 linq,你的代码会比这更清晰。

    【讨论】:

      【解决方案3】:

      你可以做这样的事情(使用 lambdas & generics & nice things like that):

      public bool LocateInAnyList(Object1 obj)
      {
          return SearchList(listTypeB, obj) || SearchList(listTypeC, obj) || SearchList(listTypeD, obj);
      }
      
      private static bool SearchList<T>(List<T> list, Object1 obj) where T : TypeA
      {
          return list.Exists(item => item.Prop1 == obj);
      }
      

      【讨论】:

      • 就个人而言,我认为这应该是公认的答案。有据可查的是,这些基于委托的方法比手动遍历列表要快。此外,它更加优雅。
      【解决方案4】:

      由于增加了方差/协方差支持,在 C# 4.0 发布之前,您将无法真正做到这一点。

      您现在可以通过允许用户传入 IEnumerable 并在将对象转换为 TypeA 时循环遍历它来破解它

      bool ContainsProp1(Object1 searchFor, IEnumerable listToSearch)
      {
         bool found = false;
      
         foreach(object obj in listToSearch)
         {
            found = ((TypeA)obj).Prop1 == searchFor;
            if (found) break;
         }
         return found;
      }
      

      【讨论】:

      • 这种情况下不需要协方差。
      【解决方案5】:

      是的。首先,您可以通过如下更改其签名来使该方法成为通用方法:

      bool ContainsProp(Object searchFor, List<T> listToSearch) : where T : TypeA {}
      

      这将允许您传递您拥有的任何列表。

      其次,我将更改第二个参数以接收列表数组:

      bool ContainsProp<T>(Object searchFor, List<T> [] listsToSearch) where T : TypeA {}
      

      这样,您可以一次传递所有列表:

      found = ContainsProp(objToSearch, listA, listB, listC);
      

      【讨论】:

      • 你检查过你的例子编译了吗?
      • 是的。它没有编译,因为我没有展示整个实现,只是方法签名,就像我在第一行中提到的那样。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多