2010-04-09 8 views
13

Ich habe eine KlasseFestlegung allgemeiner Art zur Laufzeit

public class A<T> 
{ 
    public static string B(T obj) 
    { 
     return TransformThisObjectToAString(obj); 
    } 
} 

Die Verwendung von String oben ist rein beispielhaft. Ich kann die statische Funktion wie diese gerade fein auf einem bekannten/angegebenen Typ nennen:

string s= A<KnownType>.B(objectOfKnownType); 

Wie kann ich diesen Anruf machen, wenn ich nicht weiß, T vorher, vielmehr habe ich eine Variable vom Typ Geben Sie ein, die den Typ enthält. Wenn ich dies tun:

Type t= typeof(string); 
string s= A<t>.B(someStringObject); 

Ich erhalte diese Compiler-Fehler:

Cannot implicitly convert type 't' to 'object' 
+0

Schließen [c-sharp-dynamisch-generic-type] (http://stackoverflow.com/questions/2078914/c-sharp- dynamic-generic-type) – nawfal

Antwort

9

Sie können nicht. Generische Typ-IDs müssen zum Zeitpunkt der Kompilierung bekannt sein.

bearbeiten

als andere Beiträge, scheint es möglich zu sein, indem dynamicly das Verfahren zu erzeugen und sie aufrufen - die Gefahren natürlich hat. Weitere Informationen finden Sie in den Beiträgen von Thomas und Dathan.

+0

Ich denke, ich habe die Frage falsch gelesen. Kann wirklich nichts anderes hinzufügen als das, was du gesagt hast. – ChaosPandion

+3

Es wäre genauer zu sagen, dass es keine statisch typisierte Art gibt, es zu tun; oder vielleicht auch nicht idiomatisch. Aber wie Tomas und meine Antworten zeigen, kann die Methode dynamisch aufgelöst und zur Laufzeit mit beliebigen Argumenten aufgerufen werden. – Dathan

+0

bearbeitet in, danke – Femaref

0

Wenn Sie versuchen, den Typparameter zur Laufzeit zu ersetzen, wird der ganze Zweck von type saftey, der von C# -Compiler erzwungen wird, zunichte gemacht. C# -Compiler sorgt dafür, dass Typparameter zur Kompilierzeit angegeben werden und bei Typargumenten zur Laufzeit keine Mehrdeutigkeit besteht. Ich bezweifle, dass Sie Typparameter zur Laufzeit in Generic Type ersetzen können.Specifying Typ Argument des Typs "Typ" ist fast wie mit einem ungebundenen generischen Typ.

19

Sie können dies nicht direkt ausführen, aber Sie können reflection verwenden, um zur Laufzeit einen Typparameter einer Klasse anzugeben. Ich habe nicht getestet, aber so etwas wie dies funktionieren sollte:

// We want to do something like this: 
// object o = "Hello" 
// Type t = o.GetType(); 
// 
// This is pseudo-code only: 
// string s = A<t>.B(o); 

string InvokeA(object o) { 
    // Specify the type parameter of the A<> type 
    Type genericType = typeof(A<>).MakeGenericType(new Type[] { o.GetType() }); 
    // Get the 'B' method and invoke it: 
    object res = genericType.GetMethod("B").Invoke(new object[] { o }); 
    // Convert the result to string & return it 
    return (string)res; 
} 

Natürlich stellt sich die Frage, ob dies wirklich ist, was Sie brauchen - Wenn Sie nichts über das als Argument angegeben Objekt wissen, Sie könnten auch den ganzen Code nur mit Objekt schreiben. Ich kann mir jedoch einige Szenarien vorstellen, in denen dies nützlich wäre. Ich schätze, Sie können es versuchen.

+0

Ooh, ich wusste nicht, dass Sie 'A <>' an ​​'typeof()' übergeben können. Dein Code ist definitiv sauberer als meiner. Gut gemacht. – Dathan

+0

Ich mag nicht wirklich die Tatsache, dass Sie 'A <>' in C# schreiben können, da es nicht wirklich ein Typ ist. Es ist irgendwie komisch. Wie auch immer, ich denke, es ist manchmal nützlich :-). –

+0

Schreiben 'A <>', und Zeug wie 'Äußeres <,> .Inner <,,,>' ist nützlich für ein 'typeof'" Argument ", aber es ist eine gute Sache, dass es in anderen Kontexten nicht erlaubt ist, da du recht hast C# -Typ. –

7

Es gibt absolut Unterstützung dafür im Framework und der CLR - nur nicht anmutig in C#. Mit Hilfe einer Hilfsmethode können Sie erreichen, was Sie wollen, aber mit Hilfe einer Hilfsmethode:

1

Sie können nicht. Aber Sie haben die falsche Frage für den Fall gestellt. In diesem Fall (wie in 99% der Fälle) benötigen Sie nur eine Typbeschränkung.

Versuchen:

public class A<T> where T : object 

oder, wenn T eine bekannte Klasse, eine Unterklasse ist, oder eine Schnittstelle dann wäre es besser,

public class A<T> where T : YourAbstractClass 

Einschränkungen Andere Arten existieren auch zu verwenden.Weitere Details: http://msdn.microsoft.com/en-us/library/d5x73970(VS.80).aspx

Als allgemeine Anmerkung, wenn eine neue Sprache lernen, man oft denken im Großen und Ganzen über das, was Sie wollen erreichen, nicht speziell zu finden, was Sie tun wollen. Das ist wie verbale Sprachen in der realen Welt. Es ist der Unterschied, Deutsch zu lernen, indem man ein Wörterbuch liest und die Wörter in die englische Syntax schreibt oder die Syntax lernt und die Wörter aufnimmt. Ja, ein deutscher Sprecher wird jemanden verstehen, der aus einem Wörterbuch spricht, aber die WTF pro Satz wird viel höher sein.

0

Ich erstellte diese Hilfsmethode basierend auf einigen der Antworten hier + sonst wo im Web.

Nutzung:

InvokeGenericMethodWithRuntimeGenericArguments(MyMethodWithGenericType<IType>, new[] {MyRuntimeGenericType}, null); 

Methode:

public static object InvokeGenericMethodWithRuntimeGenericArguments(Action methodDelegate, Type[] runtimeGenericArguments, params object[] parameters) 
     { 
      if (parameters == null) 
      { 
       parameters = new object[0]; 
      } 
      if (runtimeGenericArguments == null) 
      { 
       runtimeGenericArguments = new Type[0]; 
      } 

      var myMethod = methodDelegate.Target.GetType() 
         .GetMethods() 
         .Where(m => m.Name == methodDelegate.Method.Name) 
         .Select(m => new 
         { 
          Method = m, 
          Params = m.GetParameters(), 
          Args = m.GetGenericArguments() 
         }) 
         .Where(x => x.Params.Length == parameters.Length 
            && x.Args.Length == runtimeGenericArguments.Length 
         ) 
         .Select(x => x.Method) 
         .First().MakeGenericMethod(runtimeGenericArguments); 
      return myMethod.Invoke(methodDelegate.Target, parameters); 
     }