У меня есть расширение, принимающее значение перечисления в качестве параметра и возвращающее коллекцию его результата Select.

public static object Filter(this List<Base> bases, FilterType type)
{
    switch(type)
    {
        case FilterType.Alignment:
            return bases.Select(x => x.Alignment).ToList();
        case FilterType.Faction: 
            return bases.Select(x => x.Faction).ToList();   
        case FilterType.HP:
            return bases.Select(x => x.HP).ToList();  
        ...
        default:
            return null;
    }
}

И Alignment, Faction сами по себе являются перечислениями.

Такие как

public enum AlignmentType {ChaoticEvil, LawfulGood, etc.}
public enum FactionType {Human, Undead, etc.}

Таким образом, типы возврата будут соответственно List<AlignmentType>, List<FactionType>, List<int>.

Таким образом, окончательный тип возвращаемого значения неизбежно должен быть object.

Но вскоре я обнаружил, что не могу вернуть его к исходному типу (например, List<FactionType>), потому что «я не знаю, что это за тип»!

Я также не могу использовать универсальный тип, потому что результат зависит от «значения» его параметра.

И я не могу использовать полиморфизм по той же причине.

Кто-нибудь, пожалуйста, будьте добры и скажите, какие у меня есть решения?

Очень признателен!

c#
0
Noob001 20 Май 2021 в 16:07

3 ответа

Лучший ответ

Я чувствую, что ваша проблема связана с архитектурой вашего кода. «Чистый» способ заключался бы в том, чтобы иметь общий интерфейс, который будут реализовывать все ваши различные возвращаемые типы, и возвращать его список. Если у вас нет общего типа, вы всегда будете сталкиваться с этой проблемой. В противном случае вы можете разделить его на 3 метода или вернуть объект, который содержит возвращаемое значение и флаг, который указывает тип значения, но этот последний вариант должен быть последним средством.

Для вашего конкретного случая я думаю, что лучшим способом было бы разделить этот метод на три, например:

public static List<AlignmentType> FilterAlignment(this List<Base> bases)
{
    return bases.Select(x => x.Alignment).ToList();
}

public static List<FactionType> FilterFaction(this List<Base> bases)
{
    return bases.Select(x => x.Faction).ToList();
}

public static List<int> FilterHP(this List<Base> bases)
{
    return bases.Select(x => x.HP).ToList();
}
3
litelite 20 Май 2021 в 13:31

Таким образом, окончательный тип возвращаемого значения неизбежно должен быть объектом. Похоже, вы возвращаете список или ноль, поэтому тип возврата может быть IEnumerable?

https://docs.microsoft.com/en-us/dotnet/api/system.collections.ienumerable?view=net-5.0

Но вскоре я обнаружил, что не могу вернуть его к исходному типу (например, List), потому что «я не знаю, что это за тип»!

Если типов может быть несколько, вам нужно будет проверить, какой у вас тип, например

var filtered = mylist.Filter(FilterType.Alignment);
var processed = filtered switch {
    List<AlignmentType> lat => // do something
    _ => throw new Exception("not supported")
};

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression

1
Christoph Lütjen 20 Май 2021 в 13:29

Кажется, вам нужен гибкий способ выбора / сопоставления экземпляров base дочерним свойствам различного типа. Это правильно? Если да, то как насчет:

public static List<T> Map<T>(this List<Base> bases, Func<Base, T> mapper) =>  bases.Select(mapper).ToList();

Применение:

List<Base> bases = ...
List<FactionType> mappedFactions = bases.Map(b => b.Faction);
List<AlignmentType> mappedAligntments = bases.Map(b => b.Alignment);
List<int> mappedHPs = bases.Map(b => b.HP);

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

1
Fredrik 20 Май 2021 в 13:51