But in this case IDE says me that Type parameter T is never used
Nella maggior parte dei casi, è davvero molto strano dichiarare un tipo generico e quindi non usarlo.
Tuttavia, qui c'è un motivo significativo potenzialmente .
Supponiamo di avere una singola classe che, per qualche ragione, indicizza sia i Mi piace che i commenti (questa non è sempre una violazione di SRP, anche se sembra in questo esempio semplificato)
Con il tuo esempio non generico, potresti riscontrare un problema:
public class CommentsAndLikesIndexer : IIndexer
{
public void FillIndex()
{
Console.WriteLine("index filled!");
}
}
var myIndexer = new CommentsAndLikesIndexer();
Non c'è modo di segnalare che questo può essere usato per l'indicizzazione di entrambi i commenti e i Mi piace. Non c'è nemmeno modo di indicizzare solo commenti (o "mi piace") se entrambi sono implementati (a parte alcune proprietà booleane non intuitive che vanno al di fuori dell'interfaccia stessa).
Non c'è anche modo di capire che cosa myIndexer
è in grado di indicizzare.
Quando si utilizza un'interfaccia generica, è possibile specificare quali entità possono essere indicizzate:
public class CommentsAndLikesIndexer : IIndexer<Comment>, IIndexer<Like>
{
public void FillIndex()
{
Console.WriteLine("index filled!");
}
}
var myIndexer = new CommentsAndLikesIndexer();
Ora abbiamo un modo per testare cosa può essere indicizzato da myIndexer
:
bool isLikeIndexer = myIndexer is IIndexer<Like>;
bool isCommentIndexer = myIndexer is IIndexer<Comment>;
Tuttavia, il problema riguarda ancora il caso in cui FillIndex()
verrà utilizzato per entrambi i casi.
Forse è quello che vuoi. Ma supponiamo che tu voglia che siano separati. Puoi ottenere ciò utilizzando le dichiarazioni esplicite dell'interfaccia:
public class CommentsAndLikesIndexer : IIndexer<Comment>, IIndexer<Like>
{
public void IIndexer<Comment>.FillIndex()
{
Console.WriteLine("comment index filled!");
}
public void IIndexer<Like>.FillIndex()
{
Console.WriteLine("like index filled!");
}
}
E ora abbiamo implementazioni separate per un'interfaccia doppiamente implementata!
Alcuni sidenotes:
- Il downside è che quando un'interfaccia viene esplicitamente implementata, devi sempre usare l'interfaccia come tipo della variabile, per chiarire il quale metodo che vuoi usare.
-
CommentsAndLikesIndexer myIndexer = new CommentsAndLikesIndexer(); myIndexer.FillIndex();
non funziona. Il compilatore non conosce il metodo che desideri.
-
IIndexer<Comment> myIndexer = new CommentsAndLikesIndexer(); myIndexer.FillIndex();
funziona.
- Per estensione, anche% co_de dovrebbe funzionare.
- Se la tua firma del metodo sarebbe univoca in base al parametro generico (ad esempio
CommentsAndLikesIndexer myIndexer = new CommentsAndLikesIndexer(); (myIndexer as IIndexer<Comment>).FillIndex();
), potresti eseguire questa operazione senza implementazione esplicita dell'interfaccia, poiché i due metodi non saranno in conflitto.
Is it OK to use generics in cases like this (for type distinguish only)?
Quanto sopra detto, un'interfaccia generica che non usa il suo parametro di tipo generico è una cosa insolita da vedere. Esistono casi d'uso marginali per questo, ma suggerisco caldamente di verificare se questo è l'approccio migliore per te.
Se il tuo metodo è effettivamente corretto come previsto (nessun parametro di input), allora questo può essere un approccio valido.