【问题标题】:Passing a list of base class and obtain the concrete class传递基类列表并获取具体类
【发布时间】:2012-09-11 21:50:52
【问题描述】:

我有两个从基类派生的具体类。与具体的 B 类相比,具体的 A 类有十个额外的属性。我有一个方法,其中一个参数是基类列表,如下所示:List<baseClass>。在方法内部,我必须遍历列表,并转换为适当的具体类并访问属性。请让我知道如何实现这一目标。有没有好的设计模式可以做到这一点?

【问题讨论】:

    标签: c# .net oop inheritance


    【解决方案1】:

    c# 有一个 GetType 方法,您可以查看它。

    您还有is 运算符

    if (baseClass is derivedClass)
    {
        // do what you will with derived class.
    }
    

    但是

    通常你所做的首先是一个糟糕的设计模式。当您遍历基类然后强制转换为派生类时,多态性的全部意义就消失了。

    也许您可以在基类中创建一个方法来执行您需要执行的各种操作。

    【讨论】:

    • 这就是我所担心的。你能解释一下基类中方法的性质吗?
    • @user466663 在不了解问题的更多细节的情况下,很难解释解决方案的工作原理
    【解决方案2】:

    这是基本方法:

    foreach(baseClass x in theList)
    {
       if (x is classA)
       {
           classA a = (classA) x;
           ...
       }
       else if (x is classB)
       {
           classB b = (classA) x;
           ...    
       }
    }
    

    当您需要拆分多种类型时,它并没有变得更简单。您可以尝试使用接口或不同的继承模型来避免整个事情。 没有看到更多细节就不可能准确地说出来。

    【讨论】:

    • 不,您使用as 关键字,并检查null,您可以避免这样的转换。无论如何,像往常一样简单的问题,JonSkeet 以正确的答案首先到达那里。
    • @Baboon - 我相信这个硬演员将被视为 NOP。即使没有,也只是一个很小的问题,最初不值得放弃 ab 的本地声明。
    【解决方案3】:

    我猜 C# 的 dynamic 类型在这里可以成为你的朋友。

    class BaseClass {}
    
    class ConcreteClass1 : BaseClass
    {
        void Display1 () {}
    }
    
    class ConcreteClass2 : BaseClass
    {
        void Display2 () {}
    }
    
    void Enumerate (List<BaseClass> baseItems)
    {
        foreach (BaseClass baseItem in baseItems)
        {
            ConcreteAccessor ((dynamic)baseItem);
        }
    }
    
    void ConcreteAccessor (ConcreteClass1 concreteItem1)
    {
        concreteItem1.Display1 ();
    }
    
    void ConcreteAccessor (ConcreteClass2 concreteItem2)
    {
        concreteItem2.Display2 ();
    }    
    

    这里的关键是每个具体类都有不同的重载,并使用 dynamic 以无缝方式调用其中一个。美妙之处在于,在运行时解决了重载问题,使您的代码看起来很干净。

    因为它是运行时类型解析,所以不执行编译时验证。假设您错过了其中一种具体类型的重载,并且运行时将 baseItem 解析为该特定具体类型。然后它会导致运行时错误 - 崩溃 - 因为没有过载。

    另一个问题是 dynamic 在底层使用反射。如您所知,反射会减慢您的应用程序。

    【讨论】:

      【解决方案4】:
      foreach(var baseClass in baseClasses)
      {
          if(baseClass.GetType() == typeof(ClassA)
          {
             var myClassA = (ClassA) baseClass;
              dowork();
          }
          else if(baseClass.GetType() == typeof(ClassB)
          {
             var myClassB = (ClassB) baseClass;
              dowork();
          }
      
      }
      

      【讨论】:

      • 不会编译 typeof 在编译时进行评估。您需要将typeof(baseClass) 更改为baseClass.GetType()
      【解决方案5】:

      为避免显式转换,我建议您以不同的方式进行:在您的基类中放置一个抽象方法,该方法将与您的具体类的属性一起使用。

      例如:

      public abstract void DoSomethingUsingProperties();
      

      在您的具体类中使用正确的业务逻辑实现(覆盖)它。

      然后,在您的方法中,其中一个参数是基类列表,您可以执行以下操作:

      public void YourMethod(List<BaseClass> list, ...other params)
      {
          // ...
      
          foreach(var bc in list)
          {
              // so you don't need to know specific properties of concrete classes...
              bc.DoSomethingUsingProperties();
          }
      
          //...
      }
      

      【讨论】:

        猜你喜欢
        • 2016-11-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-08-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多