2009-09-09 13 views
25

Jest to kontynuacja this question na temat konwersji wartości z odbiciem. Konwersja obiektu określonego typu na inny typ można zrobić tak:Sprawdź, czy Convert.ChangeType będzie działać między dwoma typami:

object convertedValue = Convert.ChangeType(value, targetType); 

Biorąc pod uwagę dwa przypadki Type (słownie FromType i ToType), czy jest jakiś sposób, aby sprawdzić, czy konwersja uda?

E.g. mogę napisać taką metodę rozszerzenia:

public static class TypeExtensions 
{ 
    public static bool CanChangeType(this Type fromType, Type toType) 
    { 
     // what to put here? 
    } 
} 

EDYCJA: Właśnie to mam teraz. Brzydki, ale nie widzę jeszcze inny sposób ...

bool CanChangeType(Type sourceType, Type targetType) 
{ 
    try 
    { 
    var instanceOfSourceType = Activator.CreateInstance(sourceType); 
    Convert.ChangeType(instanceOfSourceType, targetType); 
    return true; // OK, it can be converted 
    } 
    catch (Exception ex) 
    { 
    return false; 
    } 
+3

tak, chciałbym metodę Convert.TryChangeType ... –

+0

@Thomas: byłoby miło, ale nie jest to dokładnie to, czego potrzebuję tutaj. Nie mam jeszcze instancji typu fromType, tylko typ. – jeroenh

+2

Myślę, że wszystko, co możesz sprawdzić w wiarygodny sposób, to fakt, że fromType implementuje 'IConvertible', ale to nie gwarantuje, że każda próba konwersji się powiedzie. – LukeH

Odpowiedz

28

właśnie napotykają ten sam problem, a ja reflektor spojrzeć na źródło changetype. ChangeType zgłasza wyjątki w 3 przypadkach:

1. conversionType is null. 
2. value is null. 
3. value does not implement IConvertible 

Po sprawdzeniu tych 3, jest zagwarantowane, że można je przekonwertować. Dzięki czemu można zaoszczędzić sporo wydajności i wyjąć try {}/catch {} blok wystarczy zaznaczyć te 3 rzeczy sobie:

public static bool CanChangeType(object value, Type conversionType) 
{ 
    if (conversionType == null) 
    { 
     return false; 
    } 

    if (value == null) 
    {    
     return false; 
    } 

    IConvertible convertible = value as IConvertible; 

    if (convertible == null) 
    { 
     return false; 
    } 

    return true; 
} 
+0

świetna odpowiedź. Powinienem sam o tym pomyśleć! – jeroenh

+0

dzięki. Zostawiłem jeden mały czek, ale to zależy od ciebie. jeśli convertible == null, ale wartość jest typu, do którego próbujesz się przekonwertować, powinieneś móc zwrócić wartość true. – esac

+26

Należy pamiętać, że nadal można wygenerować wyjątek InvalidCastException. Wygląda na to, że nie możesz nic zrobić, by to sprawdzić. Byłoby miło, gdyby IConvertible posiadało metodę CanConvertToType. – ctusch

8

Sprawdzanie Convert.ChangeType metody w reflektorze Znalazłem to w statycznym konstruktorze:

ConvertTypes = new Type[] { 
     typeof(Empty), typeof(object), typeof(DBNull), typeof(bool), typeof(char), typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal), 
     typeof(DateTime), typeof(object), typeof(string) 
    }; 

W końcu, ta metoda sprawdza tylko, czy źródło implementuje IConvertible lub czy cel jest jednym z powyższych typów ConvertTes. Więc metoda powinna wyglądać mniej więcej tak (bardzo szorstki):

return (ConvertTypes.Contains(toType) || typeof(IConvertible).IsAssignableFrom(fromType)); 
+4

Podobny do tego, o czym wspomniałem w powyższym komentarzu. Niestety sprawdzenie, czy 'Type' implementuje' IConvertible', nie jest wystarczające. Wciąż nie ma gwarancji, że każda próba konwersji się powiedzie. – LukeH

+0

W moim scenariuszu obawiam się tylko tych specjalnych prymitywów. Naprawdę chcę tylko przetestować, czy warto próbować 'ChangeType' i jest to jedyna rozsądna metoda (inna niż' try {...} catch {} ') –

+1

Prawdopodobnie lepiej byłoby użyć' HashSet 'zamiast 'Type []', jest to ważniejsze, jeśli spodziewasz się trafienia tej kontroli w ciasne pętle, aby uniknąć 'O (N)' wyszukiwania w tablicy. Wywołanie 'BinarySearch()' może być również opcja –

0

napisałem trochę ramy, która zawiera klasę Convert że może zrobić więcej niż klasa System.Convert. Jeśli jesteś zainteresowany jego użyciem, możesz pobrać go z CodePlex. Nie ma możliwości określenia, czy można przekonwertować wartości, ale wydaje się, że jest to dobra funkcja do dodania.

Czyni to możliwość konwersji wartości na podstawie:

  • IConvertible
  • TypeConverters
  • ToXxx metody
  • analizowania metody statyczne
  • parametryzowane konstruktor
  • i kilka inne drobne one

Data Type Conversions

+0

Wygląda interesująco. Sprawdzę to. – jeroenh

0

podstawie tego, co zostało już odpowiedział na oba pytania wymyśliłem tego, (potrzebuje C# 7) przykład kodu

public static object ChangeType(object value, Type conversion) 
    { 
     var type = conversion; 

     if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) 
     { 
      if (value == null) 
      { 
       return null; 
      } 

      type = Nullable.GetUnderlyingType(type); 
     } 

     return Convert.ChangeType(value, type); 
    } 

public static (bool IsSuccess, object Value) TryChangeType(object value, Type conversionType) 
    { 
     (bool IsSuccess, object Value) response = (false, null); 
     var isNotConvertible = 
      conversionType == null 
       || value == null 
       || !(value is IConvertible) 
      || !(value.GetType() == conversionType); 
     if (isNotConvertible) 
     { 
      return response; 
     } 
     try 
     { 
      response = (true, ChangeType(value, conversionType)); 
     } 
     catch (Exception) 
     { 
      response.Value = null; 
     } 

     return response; 
    } 
} 

produkcja:

public Item() 
    { 
     foreach (var pinfo in GetType().GetProperties()) 
     { 
      object value = 0; 
      var response = ReflectionHelpers.TryChangeType(value, pinfo.PropertyType); 
      if(response.IsSuccess) 
      { 
       pinfo.SetValue(this, response.Value); 
      } 
     } 
    } 

uruchamia wszystkie właściwości możliwych 0.

Powiązane problemy