【问题标题】:How do I get a particular derived object in a List<T>?如何在 List<T> 中获取特定的派生对象?
【发布时间】:2023-03-09 14:14:01
【问题描述】:

假设我有一个Fruit (List&lt;Fruit&gt; fruits = new List&lt;Fruit&gt;()) 的通用列表。然后我添加了几个对象(全部从Fruit派生)-BananaAppleOrange,但派生对象具有不同的属性(例如Banana.IsYellow)。

List<Fruit> fruits = new List<Fruit>();
Banana banana1 = new Banana();
Banana banana2 = new Banana();
Apple apple1 = new Apple();
Orange orange2 = new Orange();

fruits.Add(banana1);
fruits.Add(banana2);
fruits.Add(apple1);
fruits.Add(orange1);

那么我可以这样做:

foreach(Banana banana in fruits)
    Console.Write(banana.IsYellow);

但在执行时这当然是无效的,因为 Apple 和 Orange 对象上没有 IsYellow-property。

如何从List&lt;Fruit&gt; 只获取香蕉、苹果、橙子等?

【问题讨论】:

  • 有谁知道如何在 C++ 中做到这一点?我也陷入了这种困境,但我正在用 C++ 编写代码!

标签: c# .net list collections filter


【解决方案1】:
foreach(Banana b in fruits.OfType<Banana>())

【讨论】:

  • 哇,我不知道那个。不错!
【解决方案2】:

你可以这样做

foreach(Fruit fruit in fruits)
{
   Banana b = fruit as Banana;
   if(b != null)
   {
      Console.Write(b.IsYellow);
   }
}

【讨论】:

    【解决方案3】:

    第 1 步: 首先,您应该从水果列表中制作子列表。要制作子列表,请使用 Generic 的 FindAll()Predicate 函数。

    第 2 步: 稍后,在子集中你可以迭代,它只包含'Banana'

    这里是代码

    第一步:

    List<Fruit> fruits = new List<Fruit>();
    Banana banana1 = new Banana();
    Banana banana2 = new Banana();
    Apple apple1 = new Apple();
    Orange orange1 = new Orange();
    
    fruits.Add(banana1);
    fruits.Add(banana2);
    fruits.Add(apple1);
    fruits.Add(orange1);
    
    //Extract Banana from fruit list
    List<Fruit> bananaComb = fruits.FindAll(IsBanana);
    
    //Now iterate without worring about which fruit it is
    foreach (Fruit fruit in bananaComb)
    {
        Console.WriteLine(((Banana)fruit).IsYellow);
    }
    

    第 2 步: 谓词函数来了

    //A Predicate function to determine whether its a Banana
    static protected bool IsBanana(Fruit aFruit)
    {
        return aFruit.GetType().Name == "Banana" ? true : false;
    }
    

    【讨论】:

    • 是的,这会起作用,但是我使用的是根 UnitOfWork/Repository 上下文,因此“水果列表”将包含很多对象,复制它不是在这种情况下,这不是一个好主意。
    • 别担心。子列表并不是真正的副本,相反,它只是保存指向主列表中“香蕉”的指针。我已经检查了我的示例代码要了解有关 List.FindAll() 的更多信息,请参阅msdn.microsoft.com/en-us/library/fh1w7y8z.aspx
    【解决方案4】:

    个人觉得这个方法更易读:

    foreach(Fruit fruit in fruits)
    {
       if (fruit is Banana)
       {
          Banana b = fruit as Banana;
          Console.Write(b.IsYellow);
       }
       else if (fruit is Apple)
       {
          // ...
       }
    }
    

    【讨论】:

    • 然而,您将收到轻微的性能影响和代码分析警告,告诉您不要进行不必要的强制转换,因为您实际上是在执行两次。
    • 啊,循环 if then else 反模式 [循环 case 语句的近亲]。我的眼睛流血了。不是因为你在这里的例子,而是这些事情变成了无法维持的癌症。
    • 上面的 cmets 是有道理的,但是在 Ian 的示例中是否有更好的方法可以避免空值检查。那是让我的眼睛流血的部分。
    • 我们谈论的是水果,而 IsYellow 是对象状态(颜色或颜色)的派生属性。如果他们都有颜色(他们可能应该)然后检查它。通常使用这种模式而不是使用继承,并非所有这种情况都是错误的,但大部分时间(大多数?)似乎确实如此。参见 Fowler 的重构。
    【解决方案5】:

    添加另一种语法,但 .OfType() 可能是最好的。

    foreach (Banana b in fruits.Where(x => x is Banana))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-05-19
      • 2012-10-31
      • 2015-10-13
      • 1970-01-01
      • 2014-01-22
      • 1970-01-01
      • 2020-10-11
      • 1970-01-01
      相关资源
      最近更新 更多