2014-02-09 15 views
11

Ich bin ziemlich ratlos damit, wenn jemand irgendwelche Ideen hat. Ich habe die generische MethodeGenerische Constraints zur Laufzeit hinzufügen?

public void Foo<TClass>(TClass item) where TClass : class 
{ } 

Und ich mag diese Methode von einer anderen generischen Methode nennen, aber diese generische Methode nicht die Typeinschränkung „wo TClass: Klasse“

public void Bar<T>(T item) 
{ 
    this.Foo<T>(item); 
} 

Diese doesn ‚t Arbeit, erhalte ich die Fehler

‚Der Typ ‚T‘ ist ein Referenztyp sein, um es zu benutzen als Parameter ‚TClass‘‘

Was ich verstehe. Aber meine Frage ist das - kann ich irgendetwas mit der C# -Syntax machen, um den generischen Typ "T" zu "filtern", um ihn an "this.Bar" zu übergeben, wenn es eine Klasse ist. So etwas ....

public void Bar<T>(T item) 
{ 
    if (typeof(T).IsClass) 
     this.Foo<T **as class**>(); 
} 

Ich weiß, ich Reflektion verwenden könnte Foo zu nennen, aber dies scheint nur, wie Betrug. Kann ich etwas mit C# machen, um "T" zur Laufzeit mit der Einschränkung zu übergeben?

auch - Ich kann nicht die Einschränkung für die Methode „Bar“ ändern, da es von einer Schnittstelle kommt so die Einschränkung der Beschränkung auf der Schnittstelle zu entsprechen hat

+0

Meinten Sie "this.Foo ();" ? – Euphoric

+0

gut entdeckt - bearbeitet :) – jcharlesworthuk

+1

Also warum benutzt du 'if (typeof (T) .IsClass)' ?? –

Antwort

4

Der einzige Weg, Foo unreflektiert zu nennen, ist item zu einem der Typen/Klassen zu werfen in ihrer Hierarchie (nach dem richtigen IsClass überprüfen).

Offensichtlich gibt es nur einen Typ in seiner Hierarchie, die Sie kennen a priori: Object.

public void Bar<T>(T item) 
{ 
    if (typeof(T).IsClass) 
     this.Foo((object) item); 
} 

Edit:

, auch in einen der Kommentare Sie sagen, Sie fügt die class Einschränkung T zu instanziiert zu sein. Sie brauchen das nicht, was Sie brauchen, ist die new constraint.

+0

Wow, die tatsächlich kompiliert, ich habe total vergessen, dass Sie Generika wie diese "abkürzen" können! Ja, du hast recht, ich habe auch die neue Einschränkung gemacht, aber ich habe es aus dieser Frage heraus gelassen, um es zu vereinfachen :) – jcharlesworthuk

-1

Ich glaube, es gibt keinen Weg, es zu machen ist zu kompilieren . Sie müssen Reflektion verwenden, um den Anruf zu tätigen.

Eigentlich. Man könnte betrügen, wenn Sie es in einer Klasse enthalten:

public class Container<T> 
    { 
     public Container(T value) 
     { 
      Value = value; 
     } 

     public T Value { get; private set; } 
    } 

    public void Bar<T>(T item) 
    { 
     this.Foo<Container<T>>(new Container<T>(item)); 
    } 

aber dies fügt eine Ebene, die Sie Callthrough benötigen und macht die Typen weniger klar.

+0

Dies funktioniert nicht, da 'Container ' nicht mit 'Foo (T item)' übereinstimmt und wenn Sie es in: 'Foo (Container item)' ändern, dann wird es immer noch '' sagen T' muss ein Ref-Typ sein. –

+0

@ Some1Pr0 Was? – Euphoric

+0

er sagt, dass die Zeile 'new Container (item)' wird nicht wegen der Typ-Constraint – jcharlesworthuk

4

Leider gibt es keine Möglichkeit, dies zu tun, ohne Bar zu ändern, um die generische Einschränkung class zu haben oder Reflexion zu verwenden. Um kompilieren zu können, muss C# zur Kompilierungszeit wissen, dass T tatsächlich ein class Wert ist. Es gibt keine Möglichkeit, einen dynamischen Test wie typeof(T).IsClass zu verwenden, um diese Kompilierungszeitbeschränkung zu erfüllen.

Sie erwähnten in der Frage, dass Sie Bar nicht ändern können, aber es scheint, als ob Sie bereit sind, die Möglichkeit eines dynamischen Fehlers zu akzeptieren. Vielleicht stattdessen Foo die Einschränkung müssen sich nicht ändern, sondern eine Ausnahme auslösen, wenn T kein Klassentyp ist

+0

kompilieren Hallo danke für Sie zu beantworten. Ich habe die Beschränkung auf "Foo" gesetzt, weil ich "Foo" verwenden wollte, um eine neue Instanz des Objekts zu erstellen. Also muss "Foo" für sich genommen wirklich ein Objekt nehmen, das mit "new T()" instanziiert werden kann. Ich hätte lieber eine Laufzeitausnahme in "Bar" als "Foo". Aber wenn Reflexion die einzige Option ist, dann denke ich, das ist in Ordnung :) – jcharlesworthuk

0
if (typeof(T).IsClass) 
{ 
    this.GetType() 
     .GetMethod("Foo", System.Reflection.BindingFlags.Instance | 
          System.Reflection.BindingFlags.Public) 
     .Invoke(this, new object[] { item }); 
} 
+0

Ich bin ziemlich sicher, er fragt explizit, ob es eine Alternative zur Reflexion gibt. – Euphoric

Verwandte Themen