Написание функции для фильтрации списка элементов a по свойству его базового типа в c#

#c# #linq #types

#c# #linq #типы

Вопрос:

Допустим, у нас есть некоторые типы, определенные как so:

 public class BaseClass
{
    public int Value { get; set; }
}

public class SubClassA : BaseClass
{
    public bool SomeBoolValue { get; set; }
}

public class SubClassB : BaseClass
{
    public decimal SomeDecimalValue { get; set; }
}
  

И мы создаем два списка типа подкласса следующим образом

 List<SubClassA> subClassAList = new List<SubClassA>
{
    new SubClassA {SomeBoolValue = true, Value = 0},
    new SubClassA {SomeBoolValue = true, Value = 2},
    new SubClassA {SomeBoolValue = false, Value = 1},

};

List<SubClassB> subClassBList = new List<SubClassB>
{
    new SubClassB {SomeDecimalValue = 1.3M, Value = 2},
    new SubClassB {SomeDecimalValue = 3.5M, Value = 1},
    new SubClassB {SomeDecimalValue = 0.2M, Value = 5},
};
  

Есть ли способ реализовать функцию, которая может фильтровать как subClassAList, так и subClassBList по свойству Value?
Я знаю, что это может быть достигнуто путем приведения результатов функции следующим образом:

     public static IEnumerable<BaseClass> OrderList(IEnumerable<BaseClass> list)
    {
        return list.OrderBy(x => x.Value);
    }

...
...

        orderedAList = OrderList(subClassAList)
            .Cast<SubClassA>() //Don't like requiring a cast. Unsafe.
            .ToList();
  

Но тогда нам нужно привести результаты, чтобы вернуть их обратно в список подклассов, который не кажется очень безопасным для типов. Я знаю, что операция упорядочения сама по себе очень проста и, вероятно, не требует отдельной функции для выполнения действия, но если вы пытаетесь сделать что-то более сложное, чем упорядочивание, было бы полезно содержать логику в одной функции / классе / что угодно, чтобы добиться этого, а нечем копирование кода.

Комментарии:

1. Почему бы просто не вызвать .OrderBy(x => x.Value) список? Если вы вызываете его в a List<SubClassA> , он возвращает перечислимое SubClassA значение, если вы не приведете его к Base списку, верно?

2. Потому что, если бы вы хотели упорядочить список A и список B, вам пришлось бы писать код OrderBy(x => x.Value) дважды. Честно говоря, если это просто упорядочивание, это не составит большого труда, но я ищу решения этой небольшой проблемы, чтобы я мог получить идеи о том, как экстраполировать ее на операции, которые были бы более сложными, чем упорядочивание, и требуют нескольких шагов

Ответ №1:

Вы могли бы выполнить это с помощью универсального метода.

 public static IEnumerable<T> OrderList<T>(IEnumerable<T> list) where T : BaseClass
{
return list.OrderBy(x => x.Value);
}
  

Комментарии:

1. Спасибо, это то, что мне было нужно. Я просто применил его к более сложной функции фильтрации, которую я использовал, и она работает хорошо.

Ответ №2:

Вы можете использовать универсальный класс для решения этой проблемы, как показано ниже:

 class LinqUtil<T> where T : BaseClass
{
    static void MyMain()
    {
        List<SubClassA> subClassAList = new List<SubClassA>
        {
            new SubClassA {SomeBoolValue = true, Value = 0},
            new SubClassA {SomeBoolValue = true, Value = 2},
            new SubClassA {SomeBoolValue = false, Value = 1},

        };

        List<SubClassB> subClassBList = new List<SubClassB>
        {
            new SubClassB {SomeDecimalValue = 1.3M, Value = 2},
            new SubClassB {SomeDecimalValue = 3.5M, Value = 1},
            new SubClassB {SomeDecimalValue = 0.2M, Value = 5},
        };

        IList<SubClassA> orderedAList = LinqUtil<SubClassA>.OrderList(subClassAList)
        .ToList();

        IList<SubClassB> orderedBList = LinqUtil<SubClassB>.OrderList(subClassBList)
        .ToList();

    }

    public static IEnumerable<T> OrderList(IEnumerable<T> list) 
    {
        return list.OrderBy(x => x.Value);
    }
}
  

Ответ №3:

Вы должны добавить интерфейс для этого класса следующим образом:

  public interface IBaseClass
{
  int Value { get; set; }
}

ublic class BaseClass:IBaseClass
{
    public int Value { get; set; }
}

public class SubClassA : BaseClass,IBaseClass
{
    public bool SomeBoolValue { get; set; }
}

public class SubClassB : BaseClass,IBaseClass
{
    public decimal SomeDecimalValue { get; set; }
}
  

И теперь вы можете легко фильтровать как subClassAList, так и subClassBList по свойству Value.

 public static IEnumerable<IBaseClass> OrderList(IEnumerable<IBaseClass> list)
    {
        return list.OrderBy(x => x.Value);
    }



orderedAList = OrderList(subClassAList)
            .ToList()
  

Комментарии:

1. Разве это не похоже на приведенный мной пример? Функция orderList просто выдаст перечисление IBaseClass вместо BaseClass . Результат все равно нужно будет привести обратно к типу списка подклассов, чтобы работать с ним как со списком подклассов или подклассовb

2. но это безопасное приведение

3. все еще есть повышающая обработка в случае, если вы используете универсальный метод