Haighstrom
Haighstrom

Reputation: 617

Generics - can I write T based on a variable?

I'm writing a game and I have a Crate class which holds Item-s of type T varying by crate. I've set this up with Generics like this:

public class Crate<I> : Item 
    where I : Item
{
    private List<I> contents = new List<I>();
    //...
}

I'm currently writing a "buy" screen where you choose items, and then crates of those items are delivered. Depending on what stage the player is in the game, certain items are/aren't available. Therefore I have a list of currently available items in an array.

What I want to do is create Crates based on that array.

For example, my array might be

    public static List<Item> CurrentlyAvailableItems= new List<Item>() { new Linen(), new Food() };

From here, I want to create buttons to generate Crates of those items. At the moment the only way I can think to do it is with a giant IF loop which needs updating every time i create new items like this:

for (int i = 0; i < GV.CurrentlyAvailableItems.Count; i++)
{
    Item item = null;
    if (GV.CurrentlyAvailableItems[i] is Linen) item = new Crate<Linen>();
    else if (GV.CurrentlyAvailableItems[i] is Food) item = new Crate<Food>();
    Add(new BuyButton(item));
}

What I want to be able to do is something like:

for (int i = 0; i < GV.CurrentlyAvailableItems.Count; i++)
{
    Type t = GV.CurrentlyAvailableItems[i].GetType();
    Crate<t> crate = new Crate<t>();
    Add(new BuyButton(crateToBuy ));
}

Is this possible?

Upvotes: 1

Views: 100

Answers (2)

atlaste
atlaste

Reputation: 31146

You can do it with the dynamic keyword and function overloading for each derived type if you have only a few of them, or with reflection (see Jon Skeet's answer):

BuyButton CreateButton(MyDerivedItem foo) 
{
    return new BuyButton(Crate<MyDerivedItem>());
}

// ... and in your code:

Add(CreateButton((dynamic)(GV.CurrentlyAvailableItems[i])));

Upvotes: 2

Jon Skeet
Jon Skeet

Reputation: 1502816

You can do it with reflection:

// TODO: Consider using a foreach loop over GC.CurrentlyAvailableItems
Type itemType = GV.CurrentlyAvailableItems[i].GetType();
Type crateType = typeof(Crate<>).MakeGenericType(t);
Item crate = (Item) Activator.CreateInstance(crateType);
Add(new BuyButton(crate));

Note that this won't be terribly efficient - but it may be good enough. If it's not, you may want a Dictionary<Type, Func<Item>> or something like that.

Upvotes: 4

Related Questions