Noob001
Noob001

Reputation: 103

How to return a collection of corresponding type according to its parameter?

I have a extension taking the value of an enum as a parameter, and return a collection of its Select result.

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;
    }
}

And Alignment, Faction are each by themselves enums.

Such as

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

So the return types will be, respectively, List<AlignmentType>, List<FactionType>, List<int>.

So the final return type inevitably have to be object.

But I soon find out that I can't cast it back into its original type (eg. List<FactionType>) because "I don't know what type it is"!

I can't use generic type neither because the result is depended on the "value" of its parameter.

And I can't use polymorphism because of the same reason.

So somebody please be so kind and tell me what solutions do I have?

Much appreciated!

Upvotes: 0

Views: 90

Answers (3)

Fredrik
Fredrik

Reputation: 2317

You seem to want a flexible way to select/map instances of base to child properties of various type. Is this correct? If so how about:

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

usage:

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);

If not, then @litelite suggestions of having return types all implement a common interface is the approach I would also take.

Upvotes: 1

litelite
litelite

Reputation: 2851

I feel your problem goes down to the architecture of your code. The "clean" way would have been to have a common interface which all your different return types would implement and return a list of that. If you dont have a common type you will always be stuck with this problem. Otherwise you could split it in 3 methods or return an object wich contains the return value and a flag which indicates de type of the value but that last option should be a last resort.

For your specific case I think the best way would be to split that method in three like this :

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();
}

Upvotes: 3

Christoph L&#252;tjen
Christoph L&#252;tjen

Reputation: 5804

So the final return type inevitably have to be object. Looks like you return a list or null, so the return type could be IEnumerable?

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

But I soon find out that I can't cast it back into its original type (eg. List) because "I don't know what type it is"!

If there can be multiple types, you'll have to test, which type you have, e.g.

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

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

Upvotes: 1

Related Questions