Considérez le code suivant:
public interface IIdentifiable<T>
{
T Id { get; set; }
}
public interface IViewModel
{
}
public class MyViewModel1 : IViewModel, IIdentifiable<int>
{
public string MyProperty { get; set; }
public int Id { get; set; }
}
public class MyViewModel2 : IViewModel, IIdentifiable<string>
{
public string MyProperty { get; set; }
public string Id { get; set; }
}
J'ai aussi une classe qui fonctionne avec ViewModels:
public class Loader<T> where T: IViewModel
{
public void LoadData()
{
/*some important stuff here*/
if (typeof(IIdentifiable<??>).IsAssignableFrom(typeof(T)))
{ // ^- here's the first problem
data = data.Where(d => _dataSource.All(ds => ((IIdentifiable<??>) ds).Id != ((IIdentifiable<??>) d).Id)).ToList();
} // ^---- and there the second ----^
/*some important stuff here too*/
}
}
Maintenant, comme vous pouvez le voir, les viewmodels que j'ai pourraient implémenter l'interface IIdentifiable<>
. Je veux vérifier ça, et si c'est vrai, Je veux m'assurer que ma liste data
ne contient aucune entrée déjà présente dans ma liste _dataSourse
.
J'ai donc 2 questions:
Je ne sais pas ce que
IIdentifiable<>
a entre ses parenthèses génériques, cela pourrait êtreint
,string
ou mêmeGUID
. J'ai essayétypeof(IIdentifiable<>).IsAssignableFrom(typeof(T))
qui est la syntaxe correcte, mais elle renvoie toujoursfalse
. Existe-t-il un moyen de vérifier siT
estIIdentifiable<>
sans connaître le type générique exact?S'il y a une réponse à la première question, j'aimerais aussi savoir comment comparer les champs
Id
sans connaître leur type. J'ai trouvé cette réponse assez utile, mais elle ne couvre pas mon cas spécifique.
Je sais que je peux probablement résoudre ce problème si je fais de ma classe Loader<T>
un générique pour deux types Loader<T,K>
, où K
serait le tapez IIdentifiable<>
, mais j'aimerais savoir s'il existe d'autres solutions.
P.S. En plus de ma première question: je suis également curieux de savoir pourquoi on peut écrire quelque chose comme ça typeof(IIdentifiable<>).IsAssignableFrom(typeof(T))
s'il retourne false alors que le type générique de IIdentifiable<>
n'est pas spécifié?
Modifier: je suppose qu'avec le recul, je comprends pourquoi je ne peux pas écrire le code aussi brutalement - car il se peut qu'il y ait la collection ICollection<IViewModel>
où les entrées implémentent différents types de {{X1} } (ou ne l'implémentez pas du tout), et la vérification comme celle-ci échouerait maladroitement. Pourtant, peut-être existe-t-il un moyen de faire quelque chose comme ça avec quelques restrictions, mais sans créer un deuxième paramètre générique dans mon Loader
?
2 réponses
Essayez d'ajouter deux méthodes à votre Loader<T>
:
public bool CanCast<TId>()
{
var identifiableT = typeof(IIdentifiable<>).MakeGenericType(typeof(TId));
return identifiableT.IsAssignableFrom(typeof(T));
}
public IEnumerable<IIdentifiable<TId>> Filter<TId>(IEnumerable<T> data)
{
return data.Where(d => _dataSource.All(
ds => !((IIdentifiable<TId>) ds).Id.Equals(((IIdentifiable<TId>) d).Id)));
}
Puis dans LoadData
if (CanCast<int>())
data = Filter<int>(data);
else if (CanCast<Guid>())
data = Filter<Guid>(data);
// and so om
Nous devrions aborder votre question en deux étapes (car il y a vraiment deux problèmes à résoudre ici).
Commencez par apporter les modifications suivantes à votre interface IIdentifiable<T>
public interface IIdentifiable<T>
where T : IEquatable<T>
{
T Id { get; set; }
}
Cela garantira que vous pouvez comparer correctement les propriétés de l'ID.
Deuxièmement, dans votre méthode LoadData()
, remplacez l'instruction if
par
if (T is IIdentifiable<T>)
{ // ^- here's the first problem
data = data.Where(d => _dataSource.All(ds => ((IIdentifiable<T) ds).Id != ((IIdentifiable<T) d).Id)).ToList();
}
De nouvelles questions
c#
C # (prononcé "see sharp") est un langage de programmation multi-paradigme de haut niveau, typé statiquement développé par Microsoft. Le code C # cible généralement la famille d'outils et d'exécutions Microsoft .NET, notamment le .NET Framework, .NET Core et Xamarin. Utilisez cette balise pour les questions sur le code écrit en C # ou en spécification formelle de C #.