У меня есть расширение, принимающее значение перечисления в качестве параметра и возвращающее коллекцию его результата 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>
), потому что «я не знаю, что это за тип»!
Я также не могу использовать универсальный тип, потому что результат зависит от «значения» его параметра.
И я не могу использовать полиморфизм по той же причине.
Кто-нибудь, пожалуйста, будьте добры и скажите, какие у меня есть решения?
Очень признателен!
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();
}
Таким образом, окончательный тип возвращаемого значения неизбежно должен быть объектом. Похоже, вы возвращаете список или ноль, поэтому тип возврата может быть
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
Кажется, вам нужен гибкий способ выбора / сопоставления экземпляров 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 о том, чтобы все типы возвращаемых данных реализуют общий интерфейс, - это подход, который я бы тоже использовал.
Похожие вопросы
Связанные вопросы
Новые вопросы
c#
C # (произносится как «резкий») - это высокоуровневый, статически типизированный язык программирования с несколькими парадигмами, разработанный Microsoft. Код C # обычно нацелен на семейство инструментов и сред выполнения Microsoft .NET, включая, среди прочего, .NET Framework, .NET Core и Xamarin. Используйте этот тег для вопросов о коде, написанном на C # или в формальной спецификации C #.