2013-09-26 13 views
6

Pracuję nad aplikacją typu ETL, która tworzy jednostki z plików danych CSV. W szczególności jedno pole - pole boolowskie - okazuje się trudne, ponieważ systemy zapewniają własną interpretację wartości bool, takich jak true, false, yes, no, 1, 0, a nawet -1 itd.Jak zastąpić konwertery NET?

Korzystanie z wartości domyślnych konwertery Typ większości testów nie:

var b1 = Convert.ChangeType("true", TypeCode.Boolean, CultureInfo.InvariantCulture); 
var b2 = Convert.ChangeType("false", TypeCode.Boolean, CultureInfo.InvariantCulture); 
var b3 = Convert.ChangeType("True", TypeCode.Boolean, CultureInfo.InvariantCulture); 
var b4 = Convert.ChangeType("False", TypeCode.Boolean, CultureInfo.InvariantCulture); 
var b5 = Convert.ChangeType("TRUE", TypeCode.Boolean, CultureInfo.InvariantCulture); 
var b6 = Convert.ChangeType("FALSE", TypeCode.Boolean, CultureInfo.InvariantCulture); 

// All below fail 
var b7 = Convert.ChangeType("yes", TypeCode.Boolean, CultureInfo.InvariantCulture); 
var b8 = Convert.ChangeType("no", TypeCode.Boolean, CultureInfo.InvariantCulture); 
var b9 = Convert.ChangeType("Yes", TypeCode.Boolean, CultureInfo.InvariantCulture); 
var b10 = Convert.ChangeType("No", TypeCode.Boolean, CultureInfo.InvariantCulture); 
var b11 = Convert.ChangeType("YES", TypeCode.Boolean, CultureInfo.InvariantCulture); 
var b12 = Convert.ChangeType("NO", TypeCode.Boolean, CultureInfo.InvariantCulture); 
var b13 = Convert.ChangeType("1", TypeCode.Boolean, CultureInfo.InvariantCulture); 
var b14 = Convert.ChangeType("0", TypeCode.Boolean, CultureInfo.InvariantCulture); 

Co chciałbym zrobić, to zastąpić domyślny System.ComponentModel.BooleanConverter tak, że mogę podać mój własny parser aby poprawnie obsługiwać powyżej. Masz pomysł, jak to zrobić?

Ten post autorstwa Scotta Hanselmana dotyczy tworzenia konwerterów typów, ale chcę zastąpić domyślny.

Oto referencja dla implementacji ekstraktora.

public static TEntity ExtractEntity<TEntity>(Dictionary<string, string> row) where TEntity : class 
{ 
    var entity = Activator.CreateInstance<TEntity>(); 
    var entityType = typeof(TEntity); 

    foreach (var info in entityType.GetProperties()) 
    { 
     try 
     { 
      info.SetValue(
       entity, 
       Convert.ChangeType(row[info.Name], info.PropertyType, CultureInfo.InvariantCulture), 
       null); 
     } 
     catch {} 
    } 

    return entity; 
} 

Zasadniczo wymienia daną TEntity i dla każdego pola publicznego uzyska pozycję słownika przez jego kluczem i próbuje przekonwertować go do typu bazowego pola. Działa dobrze, z wyjątkiem boolów.

+2

Można zarejestrować niestandardowy TypeConverter dla bools stosując atrybut, a następnie użyć 'TypeDescriptor.GetConverter (info.PropertyType)', która zawsze zwrócić TypeConverter zamiast domyślnego. Użyj konwertera wynikowego, aby przekonwertować wartość na 'info.PropertyType' przed użyciem. –

+0

możliwy duplikat [Czy można zastąpić deskryptor typu dla istniejącego typu .net?] (Http://stackoverflow.com/questions/4713177/is-it-possible-to-override-the-type-descriptor- for-an-existing-net-type) –

Odpowiedz

4

Dzięki Asad I stworzył zwyczaj TypeConverter

class BoolTypeConverter : TypeConverter 
{ 
    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) 
    { 
     if (destinationType == typeof (bool)) 
     { 
      return true; 
     } 
     return base.CanConvertTo(context, destinationType); 
    } 

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) 
    { 
     if (value is string) 
     { 
      var s = value as string; 
      if (string.IsNullOrEmpty(s)) 
       return false; 
      switch (s.Trim().ToUpper()) 
      { 
       case "TRUE": 
       case "YES": 
       case "1": 
       case "-1": 
        return true; 

       default: 
        return false; 
      } 
     } 
     return base.ConvertTo(context, culture, value, destinationType); 
    } 
} 

i zarejestrowany w uruchamianiu programu:

TypeDescriptor.AddAttributes(typeof(Boolean), 
new TypeConverterAttribute(typeof(BoolTypeConverter))); 

Teraz ze zmodyfikowanym kodem wyciąg, dla każdej nieruchomości jest używany prawidłowy konwerter typu. Zwykle byłby to jeden z wbudowanych konwerterów, ale z powodu rejestracji BoolTypeConverter dla typu boolean, jest to używane.

public static TEntity ExtractEntity<TEntity>(Dictionary<string, string> row) where TEntity : class 
{ 
    var entity = Activator.CreateInstance<TEntity>(); 
    var entityType = typeof(TEntity); 

    foreach (var info in entityType.GetProperties()) 
    { 
     try 
     { 
      var converter = TypeDescriptor.GetConverter(info.PropertyType); 
      if (!converter.CanConvertTo(info.PropertyType)) continue; 

      info.SetValue(entity, converter.ConvertTo(row[info.Name], info.PropertyType)); 
     } 
     catch {} 
    } 

    return entity; 
} 
+0

Ponieważ ta odpowiedź rozwiązuje problem w pytaniu, należy oznaczyć go jako zaakceptowaną odpowiedź, klikając zaznaczenie obok niego. W ten sposób ludzie na pierwszy rzut oka stwierdzą, że problem został rozwiązany. –

+0

slick! Czy to przesłoni domyślną konwersję typu? Czy po prostu dodaje inny sposób konwersji. Mam nadzieję, że po prostu doda to inny sposób nawracania – matrixugly