di Salvatore è del tutto corretto, volevo solo descrivere il concetto un po 'meglio.
Quello che ti serve è un "vincolo di tipo generico"; per specificare che il tipo usato come T deve conformarsi a certi comportamenti (come essere derivati da un oggetto o un'interfaccia più derivati di Object), aumentando così ciò che ti è permesso fare con quell'oggetto senza ulteriori casting (che è generalmente da evitare in generici).
Come dimostra la risposta di Salvatore, CG vengono definite utilizzando il "dove" parola chiave:
public abstract class BaseViewModel<T> :
NotificationObject,
INavigationAware
where T : Entity;
{
...
Questo GTC in sostanza stabilisce che ogni T deve derivare (per quanto a distanza) da Entità. Ciò consente di trattare T come se fosse un'entità (eccetto per l'istanziazione di nuovi Ts, che richiede un GTC aggiuntivo), indipendentemente da quanto più o meno derivato il tipo di parametro generico effettivo proviene dall'entità. È possibile chiamare qualsiasi metodo visualizzato su Entity e ottenere/impostare qualsiasi campo o proprietà.
Si può anche specificare che:
- Il tipo deve essere una classe (
where T:class
), o in alternativa deve essere un ValueType (where T:struct
). Ciò consente o impedisce il confronto e l'assegnazione di un'istanza T a null, che consente anche o impedisce l'utilizzo dell'operatore con coalizione nulla ??
.
- Il tipo deve avere un costruttore di una particolare firma (
where T:new()
, where T:new(int,float)
). Ciò consente di creare istanze di Ts utilizzando la parola chiave new
, assicurando in fase di compilazione che tutti i tipi utilizzati come Ts abbiano un costruttore con la firma prevista.