Diciamo che voglio avere una classe generica Box
che può contenere qualcosa all'interno, quindi è una Box<T>
. Box<T>
ha un metodo che restituisce un Transform
Box<U>
:Modelli di template curiosamente ricorrenti con tipi generici aggiuntivi
public Box<U> Transform<U>(Func<T, U> transform)
Finora questo è stato abbastanza semplice. Tuttavia, in realtà ho bisogno di un abstract Box
, poiché il modo in cui i valori sono racchiusi e trasformati è specifico dell'implementazione. (Non posso avere un'interfaccia poiché ci sono altri metodi che sono implementati tramite la composizione di metodi astratti, ma questo non cambia comunque).
Naturalmente, voglio che i miei metodi sostituiti Transform
restituiscano una sottoclasse appropriata di Box
, non Box
stesso. Dal momento che tipi restituiti di metodi imperativi sono invarianti in C#, mi rivolgo al curiously recurring template pattern (vedi IComparable<T>
):
public abstract class Box<B, T> where B : Box<B, T>
Ora ogni classe I ereditare da Box<B, T>
dovrebbe riferirsi a se stesso o si scatena l'inferno:
public class FooBox<T> : Box<FooBox, T>
Tuttavia, questo distrugge completamente il metodo Transform
:
public abstract Box<B, U> Transform<U>(Func<T, U> transform);
fallisce la compilazione con The type 'B' cannot be used as type parameter 'B' in the generic type or method 'Test.Box<B,T>'. There is no implicit reference conversion from 'B' to 'Test.Box<B,U>'. (CS0311)
. Questo ha senso, dal momento che il tipo di ritorno è ora Box<B, U>
e B è Box<B, T>
, che non è Box<B, U>
.
La correzione semplice non funziona:
public abstract Box<B, U> Transform<U>(Func<T, U> transform) where B : Box<B, U>;
non riesce a compilare con 'Test.Box<B,T>.Transform<U>()' does not define type parameter 'B' (CS0699)
.
C'è un modo per risolvere questo, o mi sono davvero dipinto in un angolo?
si può solo fare un '' Box e trasmettere informazioni specifiche implementazione attraverso metodi di fabbrica? –
@MillieSmith rimuovendo il CRTP funzionerebbe, naturalmente, ma ciò risulterebbe nel non poter controllare quei metodi come 'Box Unisci (Riquadro un altro, Func unione)' effettivamente accetta 'Box'es compatibili. –
Alexey