2016-07-31 11 views
0

Ich habe ein Problem damit, warum ich keinen der folgenden Snippets kompiliere.Warum kann ich `this` nicht auf einen generischen Typ anwenden?

Visual Studio markiert die erste mit:

Kann nicht Typ umwandeln 'Sometype' auf 'T'

Cast ist überflüssig.

using System; 

public class SomeClass { 
    public T Coerce<T>() { 
     if (typeof(T) == typeof(SomeClass)) 
      return (T)this; // <- Error CS0030 
     else throw new InvalidCastException(); 
    } 
} 

die "redundant" cast Entfernen, ändert sich jedoch nur um den Fehler zu:

kann nicht implizit Typ umwandeln 'SomeOtherClass' auf 'T'

using System; 

public class SomeOtherClass { 
    public T Coerce<T>() { 
     if (typeof(T) == typeof(SomeOtherClass)) 
      return this; // <- Error CS0029 
     else throw new InvalidCastException(); 
    } 
} 
+0

Es würde wahrscheinlich helfen, wenn Sie erklären würden * was Sie hier erreichen *. –

+2

'return (T) (Objekt) this;' – PetSerAl

+1

Warum möchten Sie das tun? –

Antwort

2

Der Compiler sagt Ihnen genau, was falsch ist: Sie können SomeClass nicht implizit in T konvertieren, aber es gibt wirklich zwei Dinge, auf die Sie achten müssen.

Die erste Sache ist, dass Sie nicht implizit in einen generischen Typ konvertieren können, da der Typ zur Kompilierzeit nicht bekannt ist. Sie müssen es explizit umsetzen oder - wenn Sie eine implizite Konvertierung benötigen - Vererbung verwenden.

Die zweite Sache ist, dass ein wenig mehr Typ Information benötigt wird (durch Einschränkungen), um zwischen Werttypen und Referenztypen zu unterscheiden. Im Moment weiß der Compiler nichts über T. Es könnte auch eine int sein, auf die nie ein class geworfen werden kann.

Um einen Referenztyp T zu werfen müssen Sie die class Einschränkung, und es wird gut funktionieren:

public class SomeClass 
{ 
    public T Coerce<T>() where T : class 
    { 
     if (typeof(T) == typeof(SomeClass)) 
      return this as T; 
     else throw new InvalidCastException(); 
    } 
} 

Nun wird der Compiler verhindern, dass Sie auch von so etwas wie someClassInstance.Coerce<int>() tun, und das ist der Punkt .

EDIT:

Wie für das Beispiel von (T)(object)this, das funktioniert, weil man dann nicht mehr this zu T Gießen. Stattdessen wird this an object (das wird immer funktionieren, weil es ist, was alle andere Typen herrühren) und dann von object zu T, die aus dem gleichen Grund funktioniert. Sie umgehen die Kompilierzeitprüfungen.

Sie könnten dies tun und dann rufen Sie someClassInstance.Coerce<int>(), würde es Ihnen die Ausnahme geben "Angegebene Besetzung ist nicht gültig." um Laufzeit. Wenn Sie jedoch eine generische Einschränkung verwenden, erhalten Sie die Warnung Kompilierzeit.

Wenn Sie das nicht stört, ist return (dynamic)this; eine noch einfachere Lösung. Aber es vereitelt den Zweck der Verwendung von Generika.

+0

Aber warum "kehrt (T) (object) dies" Arbeit ohne Einschränkungen? –

+1

Das ist nur eine Möglichkeit, den Compiler zu tricksen, ziemlich eng verwandt mit der Verwendung von 'dynamic' (es führt zu unangenehmen Laufzeitfehlern, wenn Sie nicht zu den richtigen Typen konvertieren). Ein Objekt kann alles sein: Werttyp oder Referenztyp (und Sie können 'object' aus diesem Grund nicht als generische Einschränkung verwenden) –

+0

Meine Antwort wurde mit etwas mehr Erklärung speziell für die Implikationen dieser verschiedenen Ansätze aktualisiert. –

Verwandte Themen