2008-11-02 10 views
0

J'essaye de créer une fonction en C# qui me permettra, une fois appelée, de renvoyer une référence à un type de classe donné. Les seuls types de fonctions comme celui que j'ai vu sont dans UnrealScript et même alors la fonctionnalité est codée en dur dans son compilateur. Je me demande si je peux le faire en C#. Voici ce que je veux dire (extrait de code de la source UnrealScript):Limites de classe et archétypes

native(278) final function actor Spawn 
(
    class<actor>  SpawnClass, 
    optional actor SpawnOwner, 
    optional name  SpawnTag, 
    optional vector SpawnLocation, 
    optional rotator SpawnRotation 
); 

maintenant à UScript vous appeler comme ça ...

local ActorChild myChildRef; //Ref to ActorChild which Extends 'actor' 
myChildRef = Spawn(class'ActorChild' ...); //rest of parameters taken out 
myChildRef.ChildMethod(); //method call to method existing inside class 'ActorChild' 

qui renvoie une référence à un objet de la classe « ActorChild 'et le mettre à la variable' myChildRef. ' J'ai besoin de faire quelque chose de similaire en C#. J'ai cherché dans Generics mais il semble que pour les utiliser, j'ai besoin de créer une instance de la classe où ma fonction se trouve et de lui passer le paramètre 'generic'. Ce n'est pas très souhaitable cependant, car je n'aurai pas besoin d'utiliser la fonction 'Spawn' pour certaines classes, mais j'aurais quand même besoin d'ajouter le paramètre générique à la classe quand je l'utiliserai.

Je suppose qu'une question simplifiée serait, comment puis-je retourner un type que je ne sais pas à la compilation et quand les différentes classes pourraient être beaucoup trop à piéger.

pseudo-code (coller aux noms de classe UScript, à savoir Acteur):

//Function Sig 
public class<Actor> Create(class<Actor> CreatedClass) 
{ 
    return new CreatedClass; 
} 

//Function call 
ActorChild myChild = Create(class'ActorChild'); 

Toutes les idées?

EDIT: Je voudrais éviter les typecasts explicites qui se produiraient à partir de la classe appelant Créé. Si je peux effectuer un typage sur l'objet désiré dans la méthode Created et retourner le 'type inconnu' quel qu'il soit, je serais extrêmement heureux.

EDIT 2: Merci pour vos réponses.

Répondre

2

Plutôt que d'utiliser une classe générique, utilisez un générique méthode:

public T Spawn<T>() where T : new() 
{ 
    return new T(); 
} 

Cela dit, je suppose que vous voulez pour faire plus que juste créer une instance aveuglément, sinon vous pouvez simplement appeler new MyClass() vous-même.

+0

Merci - Apparemment, je n'ai pas assez lu. Je pensais avoir une méthode générique, vous aviez aussi besoin d'un cours générique. –

1

Vous pouvez utiliser la classe System.Type pour représenter les classes. Pour obtenir des références à des objets de type, vous soit utiliser typeof (dans un cadre où la classe est définie)

System.Type t = typeof(ActorChild); 

ou la fonction Type.GetType (si vous ne connaissez que le nom du type)

System.Type t = Type.GetType("NamespaceFoo.ActorChild"); 

vous pouvez ensuite utiliser l'API de réflexion pour créer une instance

public object Create(System.Type ClassToCreate) 
{ 
    return ClassToCreate.GetConstructor(Type.EmptyTypes).Invoke(null); 
} 
+0

ne souffre-t-il pas du problème "Type.GetType ne regarde que dans mscorlib"? – Jimmy

+0

Est-ce vraiment? Je comprends que si vous mettez, assemblyname après le nom du type, il se penchera aussi dans d'autres assemblées. Voir la documentation pour AssemblyQualifiedName dans MSDN. –

+0

Cela nécessite d'avoir à classer par 'objet' ou par 'typer' l'objet à la valeur de retour spécifiée dans la signature de la méthode. Je voudrais éviter cela. –

0

Qu'est-ce que vous essayez d'accomplir peut se faire assez facilement avec réflexion et quelque chose appelé Méthode appel dynamique.

Fondamentalement, vous utiliserez l'objet Type, la méthode Activator.CreateInstance et d'autres classes sympa telles que MethodInfo et ParameterInfo.

Voici un exemple pour vous aider à démarrer:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Reflection; 

namespace Reflection 
{ 
    class SomeClass 
    { 
     private string StringPrimer = "The parameter text is: "; 
     public SomeClass(string text) 
     { 
      Console.WriteLine(StringPrimer + text); 
     } 
     public string getPrimer() //supplies the Primer in upper case, just for kicks 
     { 
      return StringPrimer.ToUpper(); 
     } 
    } 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      SomeClass s = new SomeClass("this is an example of the classes normal hard-coded function.\nNow try feeding in some text"); 
      string t = Console.ReadLine(); 

      Console.WriteLine("Now feed in the class name (SomeClass in this case)"); 
      Type myType = Type.GetType("Reflection."+Console.ReadLine()); //Stores info about the class. 
      object myClass = Activator.CreateInstance(myType, new object[] { t }); //This dynamically calls SomeClass and sends in the text you enter as a parameter 

      //Now lets get the string primer, using the getPrimer function, dynamically 
      string primer = (string)myType.InvokeMember("getPrimer", 
                 BindingFlags.InvokeMethod | BindingFlags.Default, 
                 null, 
                 myClass, 
                 null); //This method takes the name of the method, some Binding flags, 
                   //a binder object that I left null, 
                   //the object that the method will be called from (would have been null if the method was static) 
                   //and an object array of parameters, just like in the CreateInstance method. 
      Console.WriteLine(primer); 
     } 
    } 
} 
Questions connexes