La coulée de type générique dans la requête linq
Donc, j'ai une classe qui accepte un paramètre de type générique, et il fait un peu particulières de manipulation si le paramètre type est une sous-classe d'un type donné.
IEnumerable<T> models = ...
//Special handling of MySpecialModel
if (filterString != null && typeof(MySpecialModel).IsAssignableFrom(typeof(T)))
{
var filters = filterString.Split(...);
models =
from m in models.Cast<MySpecialModel>()
where (from t in m.Tags
from f in filters
where t.IndexOf(f, StringComparison.CurrentCultureIgnoreCase) >= 0
select t)
.Any()
select (T)m;
}
Mais je suis une exception sur la dernière ligne
Cannot convert type 'MySpecialModel' to 'T'
Si j'ai modifier le code pour utiliser as
au lieu de casting, j'ai cette erreur.
The type parameter 'T' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint.
Ce qui me manque ici?
Mise à jour
Ce les besoins de la classe peut prendre n'importe quel paramètre de type, y compris struct
s et des types intégrés, donc une contrainte générique ne serait pas une solution adaptée dans mon cas.
- avez-vous fixé la contrainte
where T : class
dans votre classe générique? - Non, mais qui ne fonctionne pas dans mon cas, comme la classe générique peut accepter à la fois de référence et de la valeur des paramètres de type.
- voir mise à jour
Vous devez vous connecter pour publier un commentaire.
NeSelect(x => (MySpecialModel)x)
LINQCast<T>
méthode ne fonctionnera que pour le moulage des éléments que l'élément est déjà (comme un type de base, type dérivé, ou de l'interface). Il n'est pas prévu de jeter des objets qui peuvent être exprimées à un type de cible. (par exemple,new List<int>{1,2,3}.Cast<long>()
va lever une exception en tant que bien.La réponse ci-dessus n'était pas mauvais, mais il ne traite pas de la question.
Juste parce que vous avez prouvé avec la réflexion qu'un paramètre générique est lié à un type donné, ne signifie pas que le compilateur sait qu'il est. Pour faire ce travail, vous aurez besoin de jeter votre
T
instance d'un type commun (par exemple,object
), puis convertir le type spécifique. par exemple, (modification de la dernière ligne dans votre requête àselect (T)(object)m
devrait faire l'affaire.Select(x => (T)x)
. même résultatselect (T)(object)m
) - je n'ai pas lu la question entièrement avant de répondre.Cast<T>()
(qui est l'équivalent, et qui est plus esthétique). Si vous connaissez une raison quelconque, le double-cast serait mieux, s'il vous plaît laissez-moi savoir.MySpecialModel
, ce n'est pas rien... C'est franchement pas clair pour moi pourquoi vous utilisez un paramètre générique en premier lieu, mais si la fonctionnalité est vraiment générique, alors vous devriez probablement refactoriser le reflet de vérifier de toute façon . Je n'ai pas vraiment assez de contexte pour vous donner plus de conseils concrets...Essayez ce qui suit
Au moment de l'exécution, vous avez vérifié que
T
est un sous-type deMySpecialModel
mais le compilateur n'a pas accès à cette information au moment de la compilation. Il voit juste une tentative de conversion entre les 2 sans rapport avec les types:T
etMySpecialModel
.Pour contourner cela, vous devez utiliser
object
comme un homme du milieu. Le compilateur est capable de convertirMySpecialModel
àobject
et à aller deobject
àT
.La plus simple solution est de jeter à
object
d'abord avant de le lancer pourT
:Le problème, c'est votre chèque se produit au moment de l'exécution, mais le compilateur ne sait pas que
T
doit être une instance deMySpecialModel
dans leif
déclaration. Par conséquent, il ne voit que vous êtes en train de jeter à certains type arbitraireT
deMySpecialModel
qui n'est pas sûr, d'où l'erreur.Si vous savez que le type générique aura toujours une classe, vous pouvez ajouter une contrainte de type sur votre classe:
Autrement effectuer une double exprimés par l'objet que smartcaveman a suggéré:
T
directement àMySpecialModel
, ce qui n'est pas possible.D'utiliser le
as
mot-clé, mettre leclass
contrainte sur votre paramètre générique:struct
s'.Vous pouvez appliquer
Nullable<T>
de la contrainte, qui doit permettre la possibilité de cast (au moins à l'aide de "comme").