2009-07-08 10 views
12

Me he encontrado con un pequeño problema, y ​​no puedo encontrarlo.Sobrecargas de métodos que difieren solo por la restricción genérica

Quiero tener estos 3 sobrecargas:

public IList<T> GetList<T>(string query) where T: string 
public IList<T> GetList<T>(string query) where T: SomeClass 
public IList<T> GetList<T>(string query) where T: struct 

Obviamente la primera restricción ni siquiera se compilará solo, por lo que es mi primer número. (Me doy cuenta que podría hacerlo IList pero quiero la misma sintaxis para los tres)

De todos modos, el motivo de todo esto es que estos métodos forman parte de un proceso de ejecución de consultas SQL en una base de datos. Quiero ser capaz de devolver el resultado como una lista de cadenas (en caso de que alguien seleccione una columna varchar), una lista de tipos de valores (int, float, lo que sea) o una lista de clases (estas clases representan tablas y contienen varias columnas)

Espero que la parte sea algo comprensible :-)

De todos modos, mi gran problema es obviamente que no puedo hacer estas sobrecargas, ya que usan el mismo nombre y lista de parámetros.

Tampoco puedo combinarlos en el mismo método, ya que necesito llamar a un método en SomeClass en esa implementación, así que a menos que quiera hacer una conversión de tipo pesado, o peor, reflexión, necesito esa restricción.

Me doy cuenta de que lo que estoy tratando de hacer no es posible, entonces lo que estoy buscando es un buen enfoque, que imitará mis intenciones.

Si algo de esto es un poco confuso, sienta libre de hacer :-)

Editar:

Aquí está mi código actual para el "donde T: SomeClass" versión. Estoy tratando de añadir soporte para cuerda/valuetypes a este código actual, por lo que tal vez mi enfoque inicial es simplemente mal - cualquier idea, básicamente, son bienvenidos :-)

public IList<TValue> GetList<TValue>(string query) where TValue : DbTable, new() 
{ 
    DataSet dataSet = GetDataSet(query); 
    IList<TValue> result = new List<TValue>(); 

    if (dataSet.Tables.Count > 0) 
    { 
     foreach (DataRow row in dataSet.Tables[0].Rows) 
     { 
      TValue col = new TValue(); 
      col.Fill(row); 
      result.Add(col); 
     } 
    } 

    return result; 
} 

Como se puede ver que necesitan el tipo exacto de DbTable para crear el constructor adecuado. El relleno es un método abstracto de DbTable (que es una clase abstracta).

Respuesta

10

Como nota; no hay buenas opciones para esto. Puede considerar nombres diferentes (en lugar de sobrecargas) - GetStringList etc.

Sin embargo, me pregunto si sería más sencillo eliminar la restricción. Un solo control de tipo con "como" no es exactamente un tipo de conversión "pesado", y podría ahorrar mucho dolor.

+0

Sí nombres diferentes es simple, sin embargo, quiero hacer que sea casi como si fuera un solo y el mismo método, que acepta estas limitaciones. Podría hacer una GetList sin restricción, y luego arrojar una excepción si el tipo es incorrecto; sin embargo, en el caso de SomeClass, en realidad son clases que heredan SomeClass, y necesito el tipo exacto, ya que las nuevo(). Espera un segundo y publicaré mi GetList existente donde T: SomeClass code. – Steffen

+0

En ese caso, puede desordenarse con 'MakeGenericMethod', etc .; no es una buena opción. –

+0

Exactamente, y tiene razón en que un simple control de tipo para las cadenas y los tipos de valores no son problemáticos. Está sacando los tipos de niños de DbTable, estoy preocupado. – Steffen

0

¿qué tal esto?

public IList<T> GetList<T>(string query) where T : new() 
{ 
    // whatever you need to distinguish, this is a guess: 
    if (typeof(T).IsPrimitiveValue) 
    { 
    GetPrimitiveList<T>(query); 
    } 
    else if (typeof(T) == typeof(string)) 
    { 
    GetStringList<T>(query); 
    } 
    else 
    { 
    GetEntityList<T>(query); 
    } 

} 

private IList<T> GetStringList<T>(string query) 

private IList<T> GetPrimitiveList<T>(string query) 

private IList<T> GetEntityList<T>(string query) 
+0

Sí, eso casi funciona, el único problema es GetEntityList: como puede ver en mi ejemplo de código, necesito poder new() T y ejecutar Fill en él; ninguno es posible sin una restricción * o * reflexión (que prefiero no) El resto, sin embargo, funcionaría bien. – Steffen

+0

Necesitará un control en tiempo de ejecución para la implementación de interfaces ('como'). La reflexión no es necesaria. O bien: haga públicos los métodos con nombres específicos (GetEntityList) y llámelos directamente. –

+0

Stefan - Tengo al menos una docena de implementaciones de DbTable (ya que tengo una clase por tabla en mi base de datos), por lo que probar con as no es realmente factible, además de que las implementaciones generalmente están fuera del alcance de la biblioteca. En cuanto a llamarlo directamente, estoy empezando a creer que de hecho es la única solución: -/ – Steffen

Cuestiones relacionadas