Rzut obiektu na T

Analizuję plik XML z klasą XmlReader W. NET i pomyślałem, że byłoby mądrze napisać generyczną funkcję parsowania, aby ogólnie odczytać różne atrybuty. Wymyśliłem następującą funkcję:

private static T ReadData<T>(XmlReader reader, string value)
{
    reader.MoveToAttribute(value);
    object readData = reader.ReadContentAsObject();
    return (T)readData;
}

Jak zdałem sobie sprawę, nie działa to całkowicie tak, jak zaplanowałem; rzuca błąd w prymitywnych typach, takich jak int lub double, ponieważ cast nie może przekształcić się z string na typ numeryczny. Czy jest jakiś sposób, aby moja funkcja przeważyła w zmodyfikowanej formie?

Author: Michael Myers, 2009-05-22

8 answers

Najpierw sprawdź, czy można go rzucić.

if (readData is T) {
    return (T)readData;
} 
try {
   return (T)Convert.ChangeType(readData, typeof(T));
} 
catch (InvalidCastException) {
   return default(T);
}
 162
Author: Bob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-19 15:18:01

Czy próbowałeś przekonwertować.ChangeType ?

Jeśli metoda zawsze zwraca ciąg znaków, co wydaje mi się dziwne, ale to nie ma znaczenia, to być może ten zmieniony kod zrobiłby to, co chcesz:

private static T ReadData<T>(XmlReader reader, string value)
{
    reader.MoveToAttribute(value);
    object readData = reader.ReadContentAsObject();
    return (T)Convert.ChangeType(readData, typeof(T));
}
 15
Author: Lasse Vågsæther Karlsen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-22 19:42:15

Try

if (readData is T)
    return (T)(object)readData;
 6
Author: Sadegh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-22 19:43:16

Możesz wymagać, aby Typ był typem odniesienia:

 private static T ReadData<T>(XmlReader reader, string value) where T : class
 {
     reader.MoveToAttribute(value);
     object readData = reader.ReadContentAsObject();
     return (T)readData;
 }

A następnie wykonaj inną, która używa typów wartości i TryParse...

 private static T ReadDataV<T>(XmlReader reader, string value) where T : struct
 {
     reader.MoveToAttribute(value);
     object readData = reader.ReadContentAsObject();
     int outInt;
     if(int.TryParse(readData, out outInt))
        return outInt
     //...
 }
 3
Author: Tom Ritter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-22 19:42:49

Możesz prawdopodobnie przekazać, jako parametr, delegata, który konwertuje z ciągu znaków na T.

 2
Author: ChrisW,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-22 19:42:37

Właściwie problemem jest użycie ReadContentAsObject. Niestety, ta metoda nie spełnia swoich oczekiwań; chociaż powinna wykryć najbardziej odpowiedni typ dla wartości, w rzeczywistości zwraca łańcuch znaków, bez względu na wszystko (można to sprawdzić za pomocą reflektora).

Jednak w twoim konkretnym przypadku, znasz już typ, do którego chcesz rzucić, dlatego powiedziałbym, że używasz złej metody.

Spróbuj użyć ReadContentAs zamiast tego, to jest dokładnie to, co Ty potrzeba.

private static T ReadData<T>(XmlReader reader, string value)
{
    reader.MoveToAttribute(value);
    object readData = reader.ReadContentAs(typeof(T), null);
    return (T)readData;
}
 2
Author: baretta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-29 21:02:30

Dodaj ograniczenie 'class' (lub bardziej szczegółowe, jak klasa bazowa lub interfejs wybranych obiektów T):

private static T ReadData<T>(XmlReader reader, string value) where T : class
{
    reader.MoveToAttribute(value);
    object readData = reader.ReadContentAsObject();
    return (T)readData;
}

Lub where T : IMyInterface lub where T : new(), itd

 1
Author: Ricardo Villamil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-22 19:42:32

Właściwie, odpowiedzi przywołują interesujące pytanie, czyli to, co chcesz, aby Twoja funkcja robiła w przypadku błędu.

Może bardziej sensowne byłoby skonstruowanie go w formie metody TryParse, która próbuje odczytać w T, ale zwraca false, jeśli nie można tego zrobić?

    private static bool ReadData<T>(XmlReader reader, string value, out T data)
    {
        bool result = false;
        try
        {
            reader.MoveToAttribute(value);
            object readData = reader.ReadContentAsObject();
            data = readData as T;
            if (data == null)
            {
                // see if we can convert to the requested type
                data = (T)Convert.ChangeType(readData, typeof(T));
            }
            result = (data != null);
        }
        catch (InvalidCastException) { }
        catch (Exception ex)
        {
            // add in any other exception handling here, invalid xml or whatnot
        }
        // make sure data is set to a default value
        data = (result) ? data : default(T);
        return result;
    }

Edit: teraz, kiedy o tym myślę, czy naprawdę muszę zrobić konwersję.test typu zmiany? czy linia as już tego nie robi? Nie jestem pewien, czy robienie tego dodatkowego wywołania typu changetype właściwie to wszystko. W rzeczywistości może to po prostu zwiększyć narzut przetwarzania, generując wyjątek. Jeśli ktoś zna różnicę, która sprawia, że warto to zrobić, proszę pisać!

 1
Author: genki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-22 21:56:30