【问题标题】:How do you filter a collection of objects in a base class based on the type of the sub class created?如何根据创建的子类的类型过滤基类中的对象集合?
【发布时间】:2009-06-12 22:22:27
【问题描述】:

我写了这个例子来帮助解释。如您所见,我有一个对象层次结构。我想修改 GetFeatures() 函数以仅返回由我实例化的对象类型的构造函数添加的功能。例如,BasicModel.GetFeatures(new LuxuryModel()) 应该只返回特征“Leather Seats”和“Sunroof”。如果必须,我不介意使用反射。

Public Class Feature

    Public Sub New(ByVal model As BasicModel, ByVal description As String)
        _model = model
        _description = description
    End Sub

    Private _model As BasicModel
    Public Property Model() As BasicModel
        Get
            Return _model
        End Get
        Set(ByVal value As BasicModel)
            _model = value
        End Set
    End Property

    Private _description As String
    Public Property Description() As String
        Get
            Return _description
        End Get
        Set(ByVal value As String)
            _description = value
        End Set
    End Property

End Class


Public Class BasicModel
    Public Sub New()
        _features = New List(Of Feature)
    End Sub

    Private _features As List(Of Feature)

    Public ReadOnly Property Features() As List(Of Feature)
        Get
            Return _features
        End Get
    End Property

    Public Shared Function GetFeatures(ByVal model As BasicModel) As List(Of Feature)
        'I know this is wrong, but something like this...'
        Return model.Features.FindAll(Function(f) f.Model.GetType() Is model.GetType())
    End Function
End Class


Public Class SedanModel
    Inherits BasicModel

    Public Sub New()
        MyBase.New()
        Features.Add(New Feature(Me, "Fuzzy Dice"))
        Features.Add(New Feature(Me, "Tree Air Freshener"))
    End Sub
End Class


Public Class LuxuryModel
    Inherits SedanModel

    Public Sub New()
        MyBase.New()
        Features.Add(New Feature(Me, "Leather Seats"))
        Features.Add(New Feature(Me, "Sunroof"))
    End Sub
End Class

【问题讨论】:

    标签: .net linq reflection lambda predicate


    【解决方案1】:

    如果您想保留当前的层次结构/属性,只需创建基类的实例,然后从派生类中的特征中减去基类中的特征。

    或者,您可能需要考虑稍微更改您的类层次结构,以使您自己更轻松。

    例如,您可以将 Features 属性拆分为两个属性,例如 ModelFeatures 和 AllFeatures。

    ModelFeatures 特定于当前模型(LuxuryModel 的“Leather Seats”和“Sunroof”等)AllFeatures 返回 MyBase.AllFeatures 和 ModelFeatures 的联合。这使得获取当前模型的特性成为一个简单的属性访问。

    附:请原谅我的 VB 错误,C# 是我的首选语言。

    【讨论】:

      【解决方案2】:

      我对 VB.NET 语法并不熟悉,所以这里是应该可以使用的 C# 语法:

      public IList<Function> GetFeatures(BasicModel model)
      {
          return model.Features.Where(f => f.Model.GetType() == model.GetType()).ToList();
      }
      

      【讨论】:

      • 在 VB 中,这不会过滤任何内容。所有功能仍会返回。
      • 用 VB 或 C# 完成都无关紧要。如果您使用这样的 Where 子句,并且类型确实不同(请注意,执行 GetType 不会比较两者的基本类型,只会比较每个实例的确切类型),那么您应该得到一个过滤列表。如果它“不起作用”,那么唯一的选择是给定模型上的每个功能都适用于您传入的模型。
      【解决方案3】:

      (基于您上面的示例代码)

      说实话,我认为这不属于您的 Car Heirachy,在我看来,您希望获取静态数据并使用您的基类作为它的容器,并将您的后代类型作为键。正如你所看到的,这会导致一些简单的代码变得笨拙或过于复杂。

      我更倾向于将您的静态数据放在它所属的位置,(在这种情况下)与 Feature 类本身。我不是 VB 人,所以这段代码是用 C# 编写的。

      所以在 Feature 类本身中,有一个 static 属性(或方法)

      public static IEnumerable<Feature> GetLuxuryFeatureSets
      {
        get
        {
          yield return new Feature() { Name = "Leather Seats" };
          yield return new Feature() { Name = "Sunroof" };
        }
      }
      

      并为您的其他模型重复。因此,现在您有了一个有意义的静态数据容器,即类本身。

      【讨论】:

        【解决方案4】:

        由于无法区分一个特征和另一个特征,您需要能够询问模型它添加了哪些特征。与其在构造函​​数中将功能添加到列表中,不如使用一个方法返回特定模型添加的功能列表...

        public class LuxuryModel
        {
          public LuxuryModel
          {
             Features.Add( GetFeatures() );
          }
          public List<Features> GetFeatures()
          {
             return new List<Features>( /* new up leather and whatever */
          }
        }
        

        然后,GetFeatures 可以进行向下转换,并询问给定实例以获取该特定实例添加的功能列表...

        public List<Features> GetFeatures<T>( BasicModel model )
        {
           var m = Model as T;
           return m.GetFeatures();
        }
        

        【讨论】:

          【解决方案5】:

          如果您不希望此数据是静态的(请参阅我的其他答案),并且您希望它可以扩展到新类,并让这些类控制功能集,则可以使用另一种方法。然后使用多态性(同样是 C#,因为我不是 VB 人)

          在您的基类中创建一个返回功能的虚拟方法,在您的正统类中覆盖该属性,多态性允许您的变量作为基本模型类型,只要它们被构造为后代类型以返回正确的列表。

            public class BasicModel
            {
              public virtual IEnumerable<Feature> GetFeatures 
              {
                get
                {
                  throw new NotImplementedException();
                }
              }
            }
          
          
            public class LuxuryModel :BasicModel
            {
              public override IEnumerable<Feature> GetFeatures
              {
                get
                {
                  yield return new Feature() { Name = "Leather Seats" };
                  yield return new Feature() { Name = "Sunroof" };
                }
              }
            }
          
          
          
          private void button1_Click(object sender, EventArgs e)
          {
            StringBuilder sb = new StringBuilder();
          
            BasicModel bm = new LuxuryModel();
          
            foreach (Feature f in bm.GetFeatures)
            {
              sb.AppendLine(f.Name);
            }
            MessageBox.Show(sb.ToString());
          }
          

          【讨论】:

            猜你喜欢
            • 2020-03-31
            • 1970-01-01
            • 2020-05-21
            • 1970-01-01
            • 1970-01-01
            • 2019-05-03
            • 2014-04-04
            • 2017-06-13
            • 1970-01-01
            相关资源
            最近更新 更多