0

I have tried plugging in the code from the supposedly duplicate question several times and could never get it to work. Code from other question/answer:

(T)Activator.CreateInstance(typeof(T), new object[] { weight });

Again, as mentioned below/previously: I already tried that other question's solution and it didn't work for me. Perhaps someone could please try explaining to me how to use the other answer's code in my project rather than not actually reading my post and marking it duplicate?


I am having issues trying to get a Generic Extension method to work. My pseudo-pseudo-code:

internal static class MyExtensions
{
    public static void CreateDeck<T>(this ObservableCollection<T> deck)
    {
        ...
        Card card = null;
        if (deck.GetType() == typeof(FearCard))
        {
            card = new FearCard(i, front, back);
        }
        else if (deck.GetType() == typeof(EventCard))
        {
            card = new EventCard(i, front, back);
        }
        else if (deck.GetType() == typeof(InvaderCard))
        {
            card = new InvaderCard(i, front, back);
        }
        else if (deck.GetType() == typeof(BlightCard))
        {
            card = new BlightCard(i, front, back);
        }
        deck.Add(card);
        ...
    }
}

The rest of my code (not included) works fine, but this block needs simplified. I know this is not good code, I just wrote this out so someone could (hopefully) see what I'm actually trying to accomplish and can show me the correct way to implement this. I have tried Activator.CreateInstance but can't seem to get it to work correctly.

This is the actual code I've tried most recently:

var temp = dType;
Type[] typeArgs = { dType };
var temp2 = temp.MakeGenericType(typeArgs);
var card = Activator.CreateInstance(temp2);
deck.Add(card);

And:

dynamic card = new dynamic(i, front, back);
deck.Add(card);

And:

T card = (T)Activator.CreateInstance(typeof(T), new object[] { i, front, back });
deck.Add(card);

And other versions/attempts of the above.

But none of them work. =(

The "deck" object passed to the method will be a collection of items of one of 4 different types. I need to create objects of the corresponding type and add them to the collection. EX: if the method gets passed a deck of <type A> then i need to create a card of to put in it.

If this was non generic, the line of code would look like this:

FearCard fc = new FearCard(i, front, back);

The trick is that the item I need to create might not be a FearCard. It might be a BlightCard, or several other types. so I just need to replace this line of code with a "generic friendly" version of itself.

Note: the types FearCard, BlightCard, etc. are all derived from a public abstract class Card.

dbc
  • 104,963
  • 20
  • 228
  • 340
VoydAngel
  • 36
  • 1
  • 5
  • Are the properties corresponding to `i`, `front` and `back` read/write or immutable? – dbc Mar 24 '18 at 19:51

1 Answers1

1

Assuming that all your Card subtypes have public parameterized constructors that take three arguments corresponding to i, front and back, then you can use Activator.CreateInstance(typeof(T), params Object[]) to construct instances of your cards, where T is the ObservableCollection<T> item type.

As a concrete example, say your Card type hierarchy looks like the following:

public abstract class Card
{
    public int Index { get; private set; }
    public string Front { get; private set; }
    public string Back { get; private set; }

    public Card(int index, string front, string back)
    {
        this.Index = index;
        this.Front = front;
        this.Back = back;
    }
}

public class FearCard : Card
{
    public FearCard(int index, string front, string back) : base(index, front, back) { }
}

public class EventCard : Card
{
    public EventCard(int index, string front, string back) : base(index, front, back) { }
}

public class InvaderCard : Card
{
    public InvaderCard(int index, string front, string back) : base(index, front, back) { }
}

public class BlightCard : Card
{
    public BlightCard(int index, string front, string back) : base(index, front, back) { }
}

Then you can construct a concrete instance of a Card and add it to an ObservableCollection<T> using the following two methods:

internal static class CardExtensions
{
    public static T CreateCard<T>(int index, string front, string back) where T : Card
    {
        return (T)Activator.CreateInstance(typeof(T), index, front, back);
    }
}

internal static class MyExtensions
{
    public static T CreateDeck<T>(this ObservableCollection<T> deck, int index, string front, string back) where T : Card
    {
        if (deck == null)
            throw new ArgumentNullException();
        var card = CardExtensions.CreateCard<T>(index, front, back);
        deck.Add(card);
        return card;
    }
}

Notes:

  • Note the use of chaining of constructors in the Card type hierarchy. Derived types do not automatically inherit parameterized constructors from the base type, so public parameterized constructors must be created for each class derived from Card with consistent signatures that explicitly call the base class constructor.

  • Consider replacing the CardExtensions.CreateCard() static method with use of the factory pattern for card creation. Some references to get you started:

  • In my working example I am making some assumptions about the types of the constructor arguments i, front and back, which are not shown in your question. The specific types do not matter, but they need to be the same type throughout the Card class hierarchy. As long as that assumption is correct you can change them to match your actual types.

Sample working .Net fiddle.

dbc
  • 104,963
  • 20
  • 228
  • 340