Comment créer une méthode de conversion de type universelle

Ce que je veux faire c’est:

bool Convert( out Object output, Object source) { // find type of output. // convert source to that type if possible // store result in output. return success } 

C’est possible?

De toute évidence, il existe une structure “if” massive qui fonctionne, mais qui nécessiterait l’écriture d’un bloc if pour chaque type de données imaginable. Même en supposant que nous le limitions aux primitives et aux chaînes, cela rest un énorme morceau de code. Je pense à quelque chose d’un peu plus réfléchissant.

A part: En passant par l’API, j’ai rencontré la méthode Convert.IsDBNull (), ce qui me fera économiser beaucoup de temps.

  if ( !databasefield.GetType().Equals( DBNull.Value ) ) 

Pourquoi au nom de D.ieu est-il dans Convert? Pourquoi ne pas DBNull.IsDBNull ()?

Il n’y a pas de Saint Graal de conversion. Pour m types, vous aurez besoin de routines de conversion m * (m-1) pour couvrir toutes les permutations.

Pour les types primitifs, utilisez Convert.ChangeType

Si un type est convertible vers une primitive, il peut implémenter l’interface IConvertable et être utilisé à partir de la classe Convert.

Pour tout le rest, @Brian Rudolfs answer est le meilleur. Enregistrez une méthode de conversion explicite pour chaque permutation dont vous avez besoin.

Voici un exemple que j’utilise, vous pouvez y injecter d’autres conversions complexes en enregistrant d’autres convertisseurs de types.

 public static class Converter { public static T Convert(object obj, T defaultValue) { if (obj != null) { if (obj is T) { return (T)obj; } TypeConverter converter = TypeDescriptor.GetConverter(typeof(T)); if (converter.CanConvertFrom(obj.GetType())) { return (T)converter.ConvertFrom(obj); } } return defaultValue; } 

Un compagnon de développement a écrit exactement cette fonction, que nous trouvons extrêmement utile.

Essentiellement, il utilise la reflection pour rechercher une conversion implicite entre les deux types (recherchez “op_Implicit” pour plus d’informations).

À défaut, il recherche un constructeur du type de destination qui prend le type de source en tant que paramètre et l’appelle.

À défaut, il recherche une méthode Parse pouvant parsingr un type dans un autre. Ceci trouvera des choses comme Int32.Parse pour convertir de Ssortingng en Int ou IPAddress.Parse pour convertir de Ssortingng en IPAddress.

Pour optimiser les performances, une fois la conversion trouvée, elle est conservée dans un dictionnaire de [type, type] <==> [conversion MethodInfo], de sorte que les appels suivants ne doivent pas nécessairement faire l’object d’une recherche de reflection étendue.

Cela gère assez bien toutes les conversions de types.

J’ai rencontré votre question plusieurs fois. J’ai toujours constaté que le temps nécessaire à la création et à l’utilisation de la fonction de conversion annule le temps gagné. Éventuellement, des problèmes tels que la précision et l’arrondi se produisent et vous devez encore gérer des cas particuliers.

Pour vérifier dbnull … j’utilise typeof (object) est DbNull …

C’était un petit exercice amusant! Je viens d’écrire ceci, alors ne me bloquez pas si cela ne fonctionne pas, mais ici, j’essaie de convertir avec les différentes méthodes auxquelles je peux penser maintenant.

 public static class Converter { public static bool TryConvert(object o, out T result) { if (o == null && typeof(T).IsClass) { result = default(T); return true; } var convertible = o as IConvertible; if (convertible != null && ConvertibleHandlesDestinationType()) { result = (T)Convert.ChangeType(convertible, typeof(T)); return true; } if (o != null) { if (typeof(T).IsAssignableFrom(o.GetType())) { result = (T)o; return true; } var converter = TypeDescriptor.GetConverter(o); if (converter.CanConvertTo(typeof(T))) { result = (T)converter.ConvertTo(o, typeof(T)); return true; } } result = default(T); return false; } private static bool ConvertibleHandlesDestinationType() { return typeof(T).Equals(typeof(Boolean)) || typeof(T).Equals(typeof(Byte)) || typeof(T).Equals(typeof(char)) || typeof(T).Equals(typeof(DateTime)) || typeof(T).Equals(typeof(Decimal)) || typeof(T).Equals(typeof(Double)) || typeof(T).Equals(typeof(Int16)) || typeof(T).Equals(typeof(Int32)) || typeof(T).Equals(typeof(Int64)) || typeof(T).Equals(typeof(SByte)) || typeof(T).Equals(typeof(Single)) || typeof(T).Equals(typeof(ssortingng)) || typeof(T).Equals(typeof(UInt16)) || typeof(T).Equals(typeof(UInt32)) || typeof(T).Equals(typeof(UInt64)); } } 

Comme le paramètre de sortie est du type T, nous pouvons utiliser l’inférence de type pour que les appels ressemblent à:

 int number; if (Converter.TryConvert("123", out number)) { Debug.WriteLine(number); } 

Essayez d’utiliser des génériques. De cette façon, vous n’avez pas à effectuer toutes les vérifications de type à l’exécution que vous auriez sinon à faire (tout cela est fait au moment de la compilation).

Même avec Convert.IsDBNull, il existe un moyen bien plus efficace de vérifier:

 if (!databaseField is DBNull) 

Sachez également que vous pouvez utiliser == sur Type car il n’y a jamais qu’une seule instance de Type pour un type particulier.

Avez-vous vu cette fonction ?:

 Microsoft.VisualBasic.CType() 

J’ai écrit un article de blog sur la façon dont je gère la conversion de types à partir d’un DataRow sur mon blog. Utilisation de DataTables / Datarows

 /// /// Extension methods for manipulating DataRows /// public static class DataRowUserExtensions { ///  /// Determines whether [is null or empty ssortingng] [the specified data row]. ///  /// The data row. /// The key. ///  /// true if [is null or empty ssortingng] [the specified data row]; otherwise, false. ///  public static bool IsNullOrEmptySsortingng(this DataRow dataRow, ssortingng key) { if (dataRow.Table.Columns.Contains(key)) return dataRow[key] == null || dataRow[key] == DBNull.Value || dataRow[key].ToSsortingng() == ssortingng.Empty; throw new ArgumentOutOfRangeException(key, dataRow, "does not contain column"); } ///  /// Gets the specified data row. ///  ///  /// The data row. /// The key. ///  public static T Get(this DataRow dataRow, ssortingng key) { if (dataRow.Table.Columns.Contains(key)) return dataRow.IsNullOrEmptySsortingng(key) ? default(T) : (T) ChangeTypeTo(dataRow[key]); throw new ArgumentOutOfRangeException(key, dataRow, "does not contain column"); } ///  /// Changes the type to. ///  ///  /// The value. ///  private static object ChangeTypeTo(this object value) { if (value == null) return null; Type underlyingType = typeof (T); if (underlyingType == null) throw new ArgumentNullException("value"); if (underlyingType.IsGenericType && underlyingType.GetGenericTypeDefinition().Equals(typeof (Nullable<>))) { var converter = new NullableConverter(underlyingType); underlyingType = converter.UnderlyingType; } // Guid convert if (underlyingType == typeof (Guid)) { return new Guid(value.ToString()); } // Do conversion return underlyingType.IsAssignableFrom(value.GetType()) ? Convert.ChangeType(value, underlyingType) : Convert.ChangeType(value.ToString(), underlyingType); } }