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:

  1. Je ne sais pas ce que IIdentifiable<> a entre ses parenthèses génériques, cela pourrait être int, string ou même GUID. J'ai essayé typeof(IIdentifiable<>).IsAssignableFrom(typeof(T)) qui est la syntaxe correcte, mais elle renvoie toujours false. Existe-t-il un moyen de vérifier si T est IIdentifiable<> sans connaître le type générique exact?

  2. 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?

0
Dmitry Volkov 25 juil. 2017 à 13:05

2 réponses

Meilleure réponse

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
1
Aleks Andreev 25 juil. 2017 à 10:55

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();
    }
1
Tanveer Badar 31 juil. 2017 à 07:22