Pytanie Sprawdzanie IEnumerable z refleksją


EDYTOWAĆ 

Wersja tego pytania z gołą kością jest, jeśli mam trochę object o, w jaki sposób sprawdzić, czy o jest jakiegoś typu, który implementuje IEnumerable<string>  z refleksją? Pierwotne pytanie jest o wiele bardziej szczegółowe, ale odpowiedź na powyższe pytanie byłaby równie dobra. Przepraszam, jeśli dałem zbyt wiele szczegóły na to pytanie

EDYCJA KOŃCA

Poniżej znajduje się wymyślony POC ValueInjecter. Wszystko działa dobrze, z wyjątkiem isCollectionMapping metoda na samym dole. Próbuję uzyskać to, aby zwracać wartość true, jeśli i tylko wtedy, gdy zarówno właściwość źródłowa, jak i docelowa są dowolnymi obiektami, które implementują IEnumerable<respectiveTypes>.

próbowałem IsAssignableFrom i również IsInstanceOfType, ale nic nie działa.

Wszystko inne działa od kiedy odkomentowałem drugą linię metody, aby jawnie sprawdzić właściwości nazwy "Dzieci", działa dobrze.

Uwaga - Wiem, że są problemy z tym przykładem. Mianowicie, staram się sprawdzić dla każdego starego IEnumerable<> ale zawsze zawsze wiedząc wystarczająco, by powrócić List<>; to tylko głupi dowód koncepcji w tym momencie.

[TestClass]
public class UnitTest1 {

    [TestMethod]
    public void TestMethod1() {
        List<string> strings = new List<string>();

        Subject S = new Subject() {
            id = 1,
            SubjectName = "S1",
            Children = { new Subject() { id = 2, SubjectName = "S1a" },
                         new Subject() { id = 3, SubjectName = "S1b", Children = { new Subject() { id = 4} } } }
        };

        SubjectViewModel VM = (SubjectViewModel)new SubjectViewModel().InjectFrom<CollectionToCollection>(S); ;


        Assert.AreEqual(2, VM.Children.Count);
        Assert.AreEqual(1, VM.Children.Single(s => s.id == 3).Children.Count);
    }
}


public class Subject {
    public Subject() {
        Children = new List<Subject>();
    }

    public string SubjectName { get; set; }
    public int id { get; set; }

    public List<Subject> Children { get; set; }
}

public class SubjectViewModel {
    public SubjectViewModel() {
        Children = new List<SubjectViewModel>();
    }

    public string SubjectName { get; set; }
    public int id { get; set; }

    public List<SubjectViewModel> Children { get; set; }
}

public class CollectionToCollection : Omu.ValueInjecter.ConventionInjection {
    protected override bool Match(ConventionInfo c) {
        return c.TargetProp.Name == c.SourceProp.Name;
    }

    protected override object SetValue(ConventionInfo c) {
        if (isCollectionMapping(c))
            return (c.SourceProp.Value as IEnumerable<Subject>).Select(s => (SubjectViewModel)(new SubjectViewModel().InjectFrom<CollectionToCollection>(s))).ToList();
        else
            return c.SourceProp.Value;
    }

    private bool isCollectionMapping(ConventionInfo c) {
        return c.SourceProp.Value.GetType().IsInstanceOfType(typeof(IEnumerable<Subject>)) && c.TargetProp.Value.GetType().IsAssignableFrom(typeof(IEnumerable<SubjectViewModel>));

        //return c.SourceProp.Name == "Children" && c.TargetProp.Name == "Children";
    }
}

13
2018-04-06 13:59


pochodzenie




Odpowiedzi:


Jeśli mam jakiś przedmiot o, jak bym to zrobił   sprawdź, czy o jest tego rodzaju   przybory IEnumerable<string>?

Tak prosty jak:

o is IEnumerable<string>

Nawiasem mówiąc, twój obecny kod nie działa, ponieważ tak jest cofanie testowanie zależności powiązania (tak, jakby metoda została wywołana IsAssignableTo), tzn. przyjmuje się, że:

Bar bar = ...
Foo foo = bar

oznacza:

typeof(Bar).IsAssignableFrom(typeof(Foo)) // wrong

W rzeczywistości faktyczna implikacja jest następująca:

typeof(Foo).IsAssignableFrom(typeof(Bar))

Mianowicie, próbuję sprawdzić dla każdego   stary IEnumerable<>:

W takim przypadku musisz sprawdzić, czy typ implementuje skonstruowaną wersję ogólnego interfejsu:

o.GetType()
 .GetInterfaces()
 .Any(t => t.IsGenericType 
        && t.GetGenericTypeDefinition() == typeof(IEnumerable<>))

27
2018-04-06 14:19





Wersja tego pytania w wersji "bare-bone" polega na tym, że gdybym miał jakiś obiekt o, sprawdziłbym, czy o jest jakiegoś typu, który implementuje IEnumerable<string>?

Lubię to:

object o = whatever;
bool isSequenceOfStrings = o is IEnumerable<string>;

10
2018-04-06 14:17



Wydaje mi się, że ciężko jest mi znaleźć równowagę pomiędzy zbyt dużą ilością informacji, a zbyt małą. Muszę to zrobić z refleksją. Przepraszam za zamieszanie, Eric. :) - Adam Rackis
@Adam: Więc jakie jest pytanie? Czy pytanie brzmi "czy mam jakiś obiekt typu t, w jaki sposób sprawdziłbym, czy implementuje IEnumerable <string>?" Lub jest pytanie "Jeśli mam jakiś obiekt typu t, to w jaki sposób sprawdzić, czy t is IEnumerable <string>?" Lub jest pytanie "Jeśli mam jakiś obiekt typu t, to w jaki sposób sprawdzić, czy T jest zamienne do IEnumerable <ciąg ??" lub "... jest równe IEnumerable <T> dla dowolnego T?" lub ... To są różne pytania. Otrzymasz odpowiedź, której potrzebujesz, gdy zadasz pytanie, które naprawdę Cię interesuje. - Eric Lippert
Dlaczego musisz to robić z refleksją? - Josh G
Kiedy patrzę na próbkę kodu, widzę, że testujesz c.SourceProp.Value w stosunku do dosłownej implementacji interfejsu (IEnumerable <Subject>). Wydaje się, że nie wymaga to refleksji. c.SourceProp.Value jest IEnumerable <Subject> zwraca ten sam wynik, prawda? - Josh G
@Adam: Patrząc na twój kod, nie rozumiem, dlaczego uważasz, że musisz użyć refleksji. Co jest nie tak z "(c.SourceProp.Value jest IEnumerable <Subject>) && (c.TargetProp.Value is IEnumerable <SubjectViewModel>)" ??? - Eric Lippert


Mogłem coś przeoczyć (nie przeczytałem całej twojej próbki kodu), ale nie wydaje mi się, że potrzebujesz tutaj refleksji.

A może po prostu użyć:

if (c.SourceProp.Value is IEnumerable<Subject>)
   return true;

Jeśli nie znasz konkretnego typu, użyj generycznych:

public bool MyFunction<T>(...)
{
   if (c.SourceProp.Value is IEnumerable<T>)
      return true;
}

Lub jeśli potrzebujesz użyć interfejsu, zrób to w ten sposób (zapisuje rzutowanie):

var enumerable = c.SourceProp.Value as IEnumerable<string>;
if (enumerable != null)
{
   // Use IEnumerable<string>
   return true;
}

return false;

5
2018-04-06 14:19



Dziękuję, tak, prosta by zadziałała. Nie wiem, jak to przegapiłem. +1 - Adam Rackis