2011-01-19 13 views

risposta

11

Consente di utilizzare l'operatore as su T se è T:class.

Vieta di confrontare T con null se T è T:struct.

Si noti che se si omette T:class, è possibile confrontare T con null anche quando T è un tipo di valore.

[Nota: ho dovuto modificare questo post alcune volte prima che fosse corretto. Almeno spero che ora sia corretto.]

-1

"T: class" costringerà il tipo generico specificato a essere una classe, non un valore. Ad esempio, siamo in grado di comporre una classe ObjectList che richiede il tipo generico specificato di essere una classe, non un valore:

class ObjectList<T> where T : class { 
    ... 
} 

class SomeObject { ... } 

ObjectList<int> invalidList = new ObjectList<int>(); //compiler error 

ObjectList<SomeObject> someObjectList = new ObjectList<SomeObject>(); //this works 

Questo costringe un invariante sul tipo generico T che altrimenti potrebbero non essere applicabili. "T: struct" avrebbe funzionato allo stesso modo. Si noti che è possibile utilizzare questo costrutto anche per applicare non solo il tipo T alla classe, ma anche la corrispondenza con un'interfaccia. L'esempio di codice ho preso questo da anche ha

class MyList<T> where T : class, IEntity { ... } 

che costringe T per essere una classe e anche essere un IEntity.

+0

Grazie , ma sono consapevole della semantica dei vincoli generici - quello che sto chiedendo sono esempi in cui i vincoli struct/class sono * utili *. – Oak

1

L'utilità primaria che ho trovato in esso si trova con Marshalling e il blocco dell'oggetto in memoria.

Per esempio, faccio un sacco di lavoro con strutture interne che non possono essere auto-convertiti, o sono fatto scendere il filo come un flusso di byte, così ho scritto questo helper:

public static T PinAndCast<T>(this Array o) where T : struct 
{ 
    var handle = System.Runtime.InteropServices.GCHandle.Alloc(o, GCHandleType.Pinned); 
    T result = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); 
    handle.Free(); 
    return result; 
} 
+0

Ho pensato che la creazione di nuove istanze dipende dai vincoli "T: new()", non dai vincoli di classe/struct? Inoltre, non ho molta familiarità con Marshalling e pinning della memoria in C#, potresti forse fornire un esempio di codice? – Oak

+0

Tutto dipende dai dettagli specifici. Nei miei casi, ho avuto bisogno di convertire un set esistente di byte in una struttura. Tuttavia, la creazione di nuove istanze, in particolare, dipende dal vincolo new(). Ho modificato la mia risposta per riflettere questo. –

Problemi correlati