Как вы фильтруете коллекцию объектов в базовом классе на основе типа созданного подкласса? - PullRequest
3 голосов
/ 13 июня 2009

Я написал этот пример, чтобы помочь объяснить. Как видите, у меня есть иерархия объектов. Я хотел бы изменить функцию 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

Ответы [ 5 ]

1 голос
/ 13 июня 2009

Еще один способ сделать это, если вы не хотите, чтобы эти данные были статичными (см. Мой другой ответ), и вы хотите, чтобы они были распространяемы на новые классы и чтобы эти классы управляли наборами функций. Затем используйте полиморфизм (снова C #, поскольку я не VB парень)

В вашем базовом классе создайте виртуальный метод, который возвращает объекты, в ваших дочерних классах, переопределяющих свойство, полиморфизм позволяет вашим переменным в качестве типа 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());
}
1 голос
/ 13 июня 2009

Поскольку нет возможности отличить одну функцию от другой, вам необходимо иметь возможность спросить модель, какие функции она добавила. Вместо того, чтобы добавлять функции в список в вашем конструкторе, у вас должен быть метод, который возвращает список функций, которые добавляет конкретная модель ...

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

Затем GetFeatures мог бы выполнить downcast и запросить экземпляр, который ему дан, для списка функций, которые добавляет этот конкретный экземпляр ...

public List<Features> GetFeatures<T>( BasicModel model )
{
   var m = Model as T;
   return m.GetFeatures();
}
1 голос
/ 13 июня 2009

Я не очень знаком с синтаксисом VB.NET, поэтому вот синтаксис C #, который должен работать:

public IList<Function> GetFeatures(BasicModel model)
{
    return model.Features.Where(f => f.Model.GetType() == model.GetType()).ToList();
}
1 голос
/ 13 июня 2009

(на основе вашего примера кода выше)

Если честно, я не думаю, что это относится к вашей автомобильной иерархии, мне кажется, что вы хотите получить статические данные и использовать свой базовый класс в качестве контейнера для них с вашими потомственными типами в качестве ключа. Как видите, это приводит к некоторому неуклюжему или слишком сложному кодированию для чего-то простого.

Я был бы гораздо более склонен поместить ваши статические данные туда, где они должны быть (в данном случае) с самим классом Feature. Я не VB парень, поэтому этот фрагмент кода в C #.

Таким образом, в самом классе Feature есть static свойство (или метод)

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

И повторите для других ваших моделей. Так что теперь у вас есть контейнер для ваших статических данных, который имеет смысл, сам класс.

1 голос
/ 13 июня 2009

Если вы хотите сохранить текущую иерархию / свойства, просто создайте экземпляр базового класса и вычтите компоненты из базового класса из компонентов в производном классе.

В качестве альтернативы, вы можете немного изменить иерархию классов, чтобы облегчить себе это дело.

Например, вы можете разделить свойство Features на два свойства, например ModelFeatures и AllFeatures.

ModelFeatures относится к текущей модели ("Кожаные сиденья" и "Люк" для LuxuryModel и т. Д.) AllFeatures возвращает объединение MyBase.AllFeatures и ModelFeatures. Это делает получение функций текущей Модели тривиальным доступом к свойству.

P.S. Пожалуйста, прости мои ошибки VB, C # - мой предпочтительный язык.

...