Odczytanie pola klasy po nazwie

1
Janko M. napisał(a):
Riddle napisał(a):

Bo tam inicjujesz swoje Foo, więc pewnie wkładasz do nich to co chcesz wyciągnąć z name2.

Tak, ale muszę to zrobić w metodzie

ReadData()

Czemu niby?

Jedyny powód żeby to zrobić, to gdyby ten Foo był klasą-workiem, żeby zdeserializować jakieś dane np z tabelki lub z JSON'a, i chcesz odczytać pola tej klasy, żeby iterować po kluczach tej deserializowanej struktury.

Jeśli nie (a wygląda na to że nie), to moim zdaniem to nie jest najlepszy pomysł żeby czytać klucze klasy. Pomyśl o konsekwencjach tego, zrobisz potem refaktor, zmienisz nazwę pola, i aplikacja zacznie inaczej działać - to nie jest dobry pomysł. Zmienisz nawet kolejność pól, i aplikacja może inaczej działać, albo zrefaktorujesz ich typ - znów ten sam problem.

1
Janko M. napisał(a):

A co w przypadku kiedy zamiast:

List<Foo> records;

Mam typ generyczny:

List<T> records
Janko M. napisał(a):

W metodzie ReadData() chcę odczytać wartość pola name2, to wszystko.

Może się jednak zdecydujesz, typ generyczny czy też pole o konkretnej nazwie ...

            foreach(var rec in records)
            {
                var fields=rec
                    .GetType()
                    .GetFields()
                    .Where(field => field.IsPublic)
                    .Where(field => field.Name=="name2")
                    .Select(field => field.GetValue(rec).ToString())
                    .ToList()
                ;
                foreach(var value in fields) Console.WriteLine(value);
                Console.WriteLine();
            }

Z tym że jak mówiłem wcześniej: - nie tędy droga.

1

Model niech implementuje interfejs lub rozszerza klasę abstrakcyjną, wtedy generyczna metoda narzuca constraint, że T : IYourModelWithName2FieldWhichIsByTheWaySooGreatNameForAField i nie potrzebujesz refleksji. Refleksja to zło, bo źle użyta bardzo utrudnia refactoring, zaciemnia logikę, a za to bardzo łatwo o ukryte błędy, które wyjdą dopiero przy uruchomieniu testów lub - co dość prawdopodobne - na produkcji.

0

Problem jest taki że do metody ReadData(), wchodzą obiekty różnych klas (stąd typ generyczny). Zadaniem metody ReadData() jest na podstawie fieldName zwrócić wartość pola w danej klasie. Podane rozwiązanie przez @_13th_Dragon jest OK, pytanie co zrobić kiedy pole w klasie jest kolekcją?

public void ReadData<T>(List<T> records, string fieldName)
{

}
1
Janko M. napisał(a):

Problem jest taki że do metody ReadData(), wchodzą obiekty różnych klas (stąd typ generyczny). Zadaniem metody ReadData() jest na podstawie fieldName zwrócić wartość pola w danej klasie.

To czemu nie zrobisz że te obiekty różnych klasa mają wspólny podtym (wspólny interfejs albo wspólna klasa bazowa), i nie wyciągniesz odpowiednich danych przez metodę lub metodę abstrakcyjną?

To byłoby dużo lepsze wyjście niż czytanie pól po nazwie.

0

Teraz mi jeszcze przyszło do głowy, że możesz użyć dynamic, wtedy nie potrzebujesz generyka, ani nawet refleksji, po prostu odwołujesz się do pola jak do słownika - dynamicObject[fieldName]. Zresztą, umówmy się, nie potrzebowałeś generyka od początku, mogłeś przyjmować jako argument object.

0
Riddle napisał(a):

To czemu nie zrobisz że te obiekty różnych klasa mają wspólny podtym (wspólny interfejs albo wspólna klasa bazowa), i nie wyciągniesz odpowiednich danych przez metodę lub metodę abstrakcyjną?
To byłoby dużo lepsze wyjście niż czytanie pól po nazwie.

Problem sprowadza się do tego że i tak muszę odczytać wszystkie pola z klasy (ich nazwy i wartości) a jeśli są tam pola generyczne to też muszę odczytać ich wartości.
Czy pisząc metodę, która to robi w każdej klasie będzie to prostsze? pytam bo czegoś chyba nie rozumiem.

ŁF napisał(a):

Teraz mi jeszcze przyszło do głowy, że możesz użyć dynamic, wtedy nie potrzebujesz generyka, ani nawet refleksji, po prostu odwołujesz się do pola jak do słownika - dynamicObject[fieldName]. Zresztą, umówmy się, nie potrzebowałeś generyka od początku, mogłeś przyjmować jako argument object.

Muszę doczytać o dynamic bo go jeszcze nie używałem.

Podsumowując, spróbuję do klasy dodać metodę, która zwróci nazwę pola i wartość, może coś mi się po drodze wyjaśni.

1
Janko M. napisał(a):
Riddle napisał(a):

To czemu nie zrobisz że te obiekty różnych klasa mają wspólny podtym (wspólny interfejs albo wspólna klasa bazowa), i nie wyciągniesz odpowiednich danych przez metodę lub metodę abstrakcyjną?
To byłoby dużo lepsze wyjście niż czytanie pól po nazwie.

Problem sprowadza się do tego że i tak muszę odczytać wszystkie pola z klasy (ich nazwy i wartości) a jeśli są tam pola generyczne to też muszę odczytać ich wartości.

Wcale nie musisz, bo taka idea jak "odczytanie pola z klasy" to jest implementacja, więc nic nie musisz. Wymyśliłeś sobie takie rozwiązanie, ale ono nie jest dobre.

Janko M. napisał(a):

Czy pisząc metodę, która to robi w każdej klasie będzie to prostsze? pytam bo czegoś chyba nie rozumiem.

Prostsze raczej nie; ale trudniejsze też nie.

Po prostu wywołanie funkcji zamiast pola.

ŁF napisał(a):

Teraz mi jeszcze przyszło do głowy, że możesz użyć dynamic, wtedy nie potrzebujesz generyka, ani nawet refleksji, po prostu odwołujesz się do pola jak do słownika - dynamicObject[fieldName]. Zresztą, umówmy się, nie potrzebowałeś generyka od początku, mogłeś przyjmować jako argument object.

Muszę doczytać o dynamic bo go jeszcze nie używałem.

Podsumowując, spróbuję do klasy dodać metodę, która zwróci nazwę pola i wartość, może coś mi się po drodze wyjaśni.

Przestań odczytywać "pola" i po prostu zwróć wartości które potrzebujesz zwrócić.

Najlepiej by było, jakbyś po prostu pokazał Foo i to jak tworzysz te klasy. Nie dajesz sobie pomóc.

2

To nie ma sensu:

.GetFields()
.Where(field => field.IsPublic)

bo GetFields() zwraca tylko publiczne pola.

Ogólnie zamiast cudować z LINQ prawdopodobnie prościej type.GetField("name2").GetValue(rec).

0

Skończyło się na takim rozwiązaniu:

foreach (Object obj in records)
{
    Type type = obj.GetType();

    foreach (var f in type.GetFields())
    {
        string fName = f.Name;
        Object fValue = f.GetValue(obj);
	}
}

Potrzebuję nazwy wszystkich pól i wartości bo je raportuje, wszystkie albo na żądanie wybrane.
Dziękuję za wsparcie i sugestie.
Pozdrawiam.

1 użytkowników online, w tym zalogowanych: 0, gości: 1