.net 如何根据创建的子类的类型筛选基类中的对象集合?

.net 如何根据创建的子类的类型筛选基类中的对象集合?,.net,linq,reflection,lambda,predicate,.net,Linq,Reflection,Lambda,Predicate,我写这个例子是为了帮助解释。如你所见,我有一个对象层次结构。我想修改GetFeatures()函数,只返回由我实例化的对象类型的构造函数添加的特性。例如,BasicModel.GetFeatures(new LuxuryModel())应该只返回功能“真皮座椅”和“天窗”。如果有必要,我不介意使用反射 Public Class Feature Public Sub New(ByVal model As BasicModel, ByVal description As String)

我写这个例子是为了帮助解释。如你所见,我有一个对象层次结构。我想修改GetFeatures()函数,只返回由我实例化的对象类型的构造函数添加的特性。例如,BasicModel.GetFeatures(new LuxuryModel())应该只返回功能“真皮座椅”和“天窗”。如果有必要,我不介意使用反射

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

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

另一方面,您可能需要考虑一下更改类层次结构,以便使自己更容易。

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

ModelFeatures特定于当前车型(“用于LuxuryModel的真皮座椅”和“天窗”等)。AllFeatures返回MyBase.AllFeatures和ModelFeatures的并集。这使得获取当前模型的特性成为一种简单的属性访问


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

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

public IList<Function> GetFeatures(BasicModel model)
{
    return model.Features.Where(f => f.Model.GetType() == model.GetType()).ToList();
}
public IList GetFeatures(基本模型)
{
返回model.Features.Where(f=>f.model.GetType()==model.GetType()).ToList();
}
(基于上面的示例代码)

老实说,我认为这不属于你的车继承人,在我看来,你想要获取静态数据,并使用你的基类作为它的容器,使用你的Decentant类型作为密钥。正如您所看到的,这会导致对一些简单的东西进行一些笨拙或过于复杂的编码

我更倾向于将静态数据放在它所属的地方,(在本例中)与要素类本身放在一起。我不是一个VB的家伙,所以这段代码是C#

因此,在要素类本身中,有一个静态属性(或方法)

公共静态IEnumerable GetLuxuryFeatureSet
{
得到
{
返回新功能(){Name=“Leather Seats”};
产生返回新特性(){Name=“天窗”};
}
}

对其他型号重复上述步骤。因此,现在您有了一个用于存储有意义的静态数据的容器,即类本身。

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

public class LuxuryModel
{
  public LuxuryModel
  {
     Features.Add( GetFeatures() );
  }
  public List<Features> GetFeatures()
  {
     return new List<Features>( /* new up leather and whatever */
  }
}
公共级豪华模型
{
公共豪华模型
{
添加(GetFeatures());
}
公共列表GetFeatures()
{
返回新列表(/*新的皮革和其他*/
}
}
然后,GetFeatures可以进行向下转换,并要求实例提供该实例添加的功能列表

public List<Features> GetFeatures<T>( BasicModel model )
{
   var m = Model as T;
   return m.GetFeatures();
}
public List GetFeatures(基本模型)
{
var m=模型为T;
返回m.GetFeatures();
}

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

在基类中创建一个返回特性的虚拟方法,在Decent类中重写属性,多态性允许变量作为类型basicmodel,只要它们被构造为后代类型,就可以返回正确的列表

  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());
}
公共类基本模型
{
公共虚拟IEnumerable GetFeatures
{
得到
{
抛出新的NotImplementedException();
}
}
}
公共级豪华模型:BasicModel
{
公共覆盖IEnumerable GetFeatures
{
得到
{
返回新功能(){Name=“Leather Seats”};
产生返回新特性(){Name=“天窗”};
}
}
}
私有无效按钮1\u单击(对象发送者,事件参数e)
{
StringBuilder sb=新的StringBuilder();
BasicModel bm=新豪华车型();
foreach(bm.GetFeatures中的特性f)
{
某人的姓名;
}
Show(sb.ToString());
}

在VB中,这不会过滤任何内容。所有功能仍将返回。无论是在VB中还是在C#中完成,这都不重要。如果使用类似的Where子句,并且类型确实不同(请注意,执行GetType不会比较这两个实例的基类型,只会比较每个实例的确切类型),那么你应该得到一个过滤列表。如果它“不工作”,那么唯一的选择就是给定模型上的每个特性都是针对你传入的模型的。
  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());
}