TheNormalPerson
TheNormalPerson

Reputation: 591

can't use type stored in a type array

I have a base class called a, and it has a virtual function called Foo

class a
{
    public virtual void Foo() {}
}

And i have a bunch of other classes inheriting from it.

class B : A{}
class C : A{}
class D : A{}
class E : A{}

Now, i want to have an array of the types so i can choose one by random so i tried this:

class Boo
{
    Type[] options;
    public Boo()
    {
        options = new[]
        {
            typeof(B),
            typeof(C),
            typeof(D),
            typeof(E)
        };
    }
}

And then i want to choose one at random and use its Foo method and i did it like this:

Random rnd = new Random();
(options[rnd.Next(options.Length)] as A).Foo()

But this doesn't work, is there any way of accomplishing this?

(Btw, i didn't have a good name for this so if anyone has a better name they can feel free to edit :) )

Upvotes: 2

Views: 90

Answers (4)

Georg Patscheider
Georg Patscheider

Reputation: 9463

options should be an array of A-instances, not a Type[].

class Boo {
    public A[] options;
    public Boo() {
        options = new[] {
            new B(),
            new C(),
            new D(),
            new E()
        };
    }
}

C# fiddle

Upvotes: 5

Matthew Watson
Matthew Watson

Reputation: 109567

Other answers have already described how to fix your original code.

However, as an alternative, you could just use a switch statement or similar approach:

public static A RandomlyCreateA(Random rng)
{
    switch (rng.Next(4))
    {
        case 0: return new B();
        case 1: return new C();
        case 2: return new D();
        case 3: return new E();

        default: throw new InvalidOperationException("Can't happen!");
    }
}

Or if you want to use reflection to choose randomly from all types that inherit from class A (that are defined in the same assembly as class A):

public static A RandomlyCreateA(Random rng)
{
    var types = Assembly.GetAssembly(typeof(A)).GetTypes().Where(t => t.IsSubclassOf(typeof(A))).ToArray();
    return Activator.CreateInstance(types[rng.Next(types.Length)]) as A;
}

Upvotes: 0

dcg
dcg

Reputation: 4219

If you want to invoke Foo you have to create an instance first, then invoke:

((options[rnd.Next(options.Length)].GetConstructor(new Type[0]).Invoke(null)) as A).Foo()

Upvotes: 0

Ivan Mladenov
Ivan Mladenov

Reputation: 1847

You cannot do that because your options array holds the types themselves, not instances.

You can do something like

Random rnd = new Random();
var type = options[rnd.Next(options.Length)]
var instance = Activator.CreateInstance(type) as A;
instance.Foo();

Upvotes: 1

Related Questions