2015-12-30 6 views
5

Ho un metodo incredibilmente brutto che dovrebbe estrarre dati assortiti da un database e usarlo per costruire un oggetto di un tipo richiesto. L'obiettivo è di portare la bruttezza assortita in un unico posto, in modo che le classi che derivano dalla classe contenente questo metodo possano essere relativamente pulite.Come trasmettere un oggetto a un tipo di ritorno generico, quando il tipo restituito è un'interfaccia generica?

non sto avendo un problema con cui si suppone di restituire un singolo oggetto, anche quando il tipo è nullable:

protected T getValue<T>(ParameterObject myParameterObject) 
{ 
    var typeOfT = typeof (T); 

    if (typeOfT == typeof(bool)) 
    { 
     string val = this.getValue(myParameterObject); 

     if (val == null) 
      return default(T); 

     bool rVal; 
     if (!Boolean.TryParse(val, out rVal)) 
      return default(T); 

     return changeType<T>(rVal); 
    } 

    if (typeOfT == typeof (double?)) 
    { 
     string val = this.getValue(myParameterObject); 

     if (val == null) 
      return default(T); 

     double rVal; 
     if (!Double.TryParse(val, out rVal)) 
      return default(T); 

     return changeType<T>(rVal); 
    } 

    [...] 
} 

public static T changeType<T>(object value) 
{ 
    var t = typeof(T); 
    if (!t.IsGenericType || t.GetGenericTypeDefinition() != typeof(Nullable<>)) 
     return (T)Convert.ChangeType(value, t); 

    if (value == null) 
     return default(T); 

    t = Nullable.GetUnderlyingType(t); 
    return (T)Convert.ChangeType(value, t); 
} 

Purtroppo, non ho i casi in cui il mio tipo di ritorno desiderato è IList, dove voglio tornare un elenco:

protected T getValue<T>(ParameterObject myParameterObject) 
{ 
    var typeOfT = typeof (T); 

    if (typeOfT.IsGenericType) 
    { 
     if (typeOfT.GetGenericTypeDefinition() == typeof (IList<>)) 
     { 
      var genericArgumentType = typeOfT.GenericTypeArguments.FirstOrDefault(); 
      var baseType = typeof (List<>); 
      var genericType = baseType.MakeGenericType(new[] {genericArgumentType}); 

      var rVal = Activator.CreateInstance(genericType); 

      [code to populate the list] 

      return changeType<T>(rVal); 
     } 

    [...] 
} 

non posso restituire un rval, perché è un oggetto, non è un caso di T. Ma la funzione mio changeType() sta venendo a mancare, con un errore:

System.InvalidCastException: Object must implement IConvertible.

Quindi, ho un metodo generico per il quale il tipo restituito è IList, e ho un oggetto che è un elenco, ma il mio riferimento ad esso è di tipo Oggetto. Come posso lanciarlo in modo che possa restituirlo dalla funzione?

+2

Scusa se mi manca qualcosa di ovvio, ma perché stai facendo 'return changeType (rVal);' invece di 'return (T) (object) rVal;'? – 31eee384

risposta

1

La linea return (T)Convert.ChangeType(value, t); non funziona perché l'oggetto value non implementa IConvertible.

Da MSDN docs

[...] For the conversion to succeed, value must implement the IConvertible interface, because the method simply wraps a call to an appropriate IConvertible method. The method requires that conversion of value to conversionType be supported.

Per risolvere questo problema, non sono sicuro di un modo generale, ma per il caso specifico di value essere di un tipo o di IEnumerableIEnumerable<>, allora si potrebbe provare a lanciare quindi eseguire una value.Select(x => changeType<ListGenT>(x)) query linq. Usando ricorsivamente il tuo metodo changeType, questo dovrebbe gestire anche i tipi generici nidificati.

+0

Non sono ancora sicuro di aver capito, ma se ho cambiato i miei metodi per restituire l'elenco , invece di creare un elenco e restituire un IList , il problema è andato via. –