2017-10-17 17 views
2

J'ai une classe de base appelée, et il a une fonction virtuelle appelée Foone peut pas utiliser le type stocké dans un tableau de type

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

et moi avons un tas d'autres classes héritant de celui-ci.

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

Maintenant, je veux avoir un tableau des types que je puisse choisir un par hasard si je l'ai essayé ceci:

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

Et puis je veux choisir un au hasard et d'utiliser son Foo méthode et je l'ai fait comme ceci:

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

Mais cela ne fonctionne pas, y at-il un moyen d'accomplir cela?

(BTW, je n'avais pas un bon nom pour ce donc si quelqu'un a un meilleur nom, ils peuvent se sentir libres de modifier :))

+0

Que voulez-vous dire par "ne fonctionne pas"? Des erreurs? –

+0

options contient type, où Foo() attend une instance. – qxg

+0

'options [rnd.Next (options.Length)] comme A' devrait être' null' donc une exception 'NullReferenceException' est levée. – dcg

Répondre

5

options devrait être un tableau de A -instances, pas Type[].

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

C# fiddle

1

Vous ne pouvez pas le faire parce que votre tableau options détient les types eux-mêmes, pas d'instances.

Vous pouvez faire quelque chose comme

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

Si vous voulez appeler Foo vous devez créer une instance d'abord, puis invoquez:

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

D'autres réponses ont déjà décrit comment fixer votre code d'origine.

Cependant, comme alternative, vous pouvez simplement utiliser une instruction switch ou approche similaire:

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!"); 
    } 
} 

Ou si vous voulez utiliser la réflexion pour choisir au hasard parmi tous les types qui héritent de class A (qui sont définis dans le même assemblage que 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; 
} 
+0

Merci, mais je veux éviter les déclarations swtich, pour une meilleure flexibilité – TheNormalPotato