2010-01-05 29 views
6

Tengo un problema simple.Envolviendo una clase no heredable en C#

Quiero decorar la clase SqlDataReader para que cuando se invoquen los métodos de eliminación o cierre, pueda disponer de un recurso oculto al mismo tiempo.

la clase SqlDataReader no es heredable.

¿Cómo puedo lograr esto? Realmente no quiero implementar el DbDataReader, IDataReader, IDisposable & Interfaces IDataRecord

+0

¿Qué quiere decir no heredable? ¿Es una clase sellada? ¿Podrías elaborar sobre las interfaces? ¿NO TIENES que implementar esos? Además, ¿por qué NO quieres? –

+0

SqlDataReader no está sellado, por lo que es hereditario, pero sus constructores son privados, por lo que no puede satisfacer al constructor base cuando hereda de él; solo estoy criticando los detalles, pero aún así, tiene razón. –

+0

Además de mi comentario sobre la respuesta de sedoso, no puedo evitar preguntarme ... ¿qué podrías necesitar empaquetar con un 'SqlDataReader'? Realmente espero que no sea un 'SqlCommand' o' SqlConnection' ... – Aaronaught

Respuesta

5

Incluso si pudieras heredar de SqlDataReader, no importaría de todos modos porque no podrías hacer que SqlCommand creara una instancia de tu clase derivada.

La implementación de IDataReader en un contenedor no es nada difícil cuando simplemente se está deferiendo al SqlDataReader subyacente. Es un poco lento, pero no tan malo.

Pero tengo curiosidad, ¿el recurso que desea eliminó la conexión? De ser así, hay un miembro CloseConnection de la enumeración CommandBehavior que asegura que la conexión se cerrará cuando se cierre el lector de datos.

var reader = command.ExecuteReader(CommandBehavior.CloseConnection); 
... 
reader.Close(); // also closes connection 

Tenga en cuenta que Cerrar/Eliminar son lo mismo en SqlDataReader.

Finalmente, aquí hay una última sugerencia que me ha servido bien en el pasado. Tenga en cuenta que en el siguiente ejemplo, es dueño del SqlDataReader de principio a fin, aunque está "cediendo" a la persona que llama en cada registro.

private static IEnumerable<IDataRecord> GetResults(this SqlCommand command) { 
    using (var myTicket = new MyTicket()) 
    using (var reader = command.ExecuteReader()) { 
     while (reader.Read()) { 
      yield return reader; 
     } 
    } 
    // the two resources in the using blocks above will be 
    // disposed when the foreach loop below exits 
} 

... 

foreach (var record in myCommand.GetResults()) { 

    Console.WriteLine(record.GetString(0)); 

} 

// when the foreach loop above completes, the compiler-generated 
// iterator is disposed, allowing the using blocks inside the 
// above method to clean up the reader/myTicket objects 
+0

El recurso es un ticket desechable que se usa para proteger el acceso a la base de datos SQL. –

+0

De acuerdo, agregué otra sugerencia en mi respuesta que podría ayudar. – Josh

+0

Esa es una solución muy interesante. ¿Cuáles son las ideas de las personas sobre esto? –

3

Invertirlo; utilice su recurso "Oculto" como principal, implemente IDisposable, y luego cierre el DataReader cuando haya terminado con él.

+0

Preferiría que el código de llamada no supiera nada al respecto. Actualmente está esperando una instancia de SqlDataReader –

+4

¿Es usted propietario del código de llamada? ¿Realmente necesita aceptar un 'SqlDataReader'? Eso es algo que debes tratar de evitar; si puede hacer que acepte un 'IDataReader' en su lugar, puede envolver' SqlDataReader' con bastante facilidad. – Aaronaught

+0

Sí, soy el propietario del código de llamada. Prefiero no tener que envolver la clase (implementar IDataReader) –

1

http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.aspx La clase no está sellada. Debería simplemente llamar a base.dispose() al comienzo de su anulación y luego poner su código después.

no tengo a mi IDE frente a mí, sino que debe mirar algo como

public myClass : SqlDataReader 
{ 
    protected overide void Dispose(bool disposing) : Base(disposing) 
    { 
     myCleanupCode(); 
    } 
    protected overide void Dispose() 
    { 
     myCleanupCode(); 
    } 
    private myCleanupCode() 
    { 
     //Do cleanup here so you can make one change that will apply to both cases. 
    } 
} 

EDITAR --- Basta con leer los comentarios orginal, veo que tiene el constructor privado, vamos que explota mi VS2008 y BRB enferma

mirando a ella, y todo el mundo está tratando estas soluciones de fantasía, la única cosa que veo que se puede hacer es

public class myClass : IDisposable 
{ 

    public SqlDataReader dataReader { get; set; } 

    #region IDisposable Members 

    public void Dispose() 
    { 
     dataReader.Dispose(); 
     //My dispose code 
    } 

    #endregion 
} 

EDIT --- Suspiro, esto es excatly lo que Silky publicó hace 40 min.

+0

Este código causa los ERRORES COMPILAR: Error # 1 El tipo 'System.Data.SqlClient.SqlDataReader' no tiene constructores definidos ... y ... Error # 2 'System.Data.SqlClient.SqlDataReader.SqlDataReader (System.Data.SqlClient.SqlCommand, System.Data.CommandBehavior)' es inaccesible debido a su nivel de protección –

+0

primera línea de su enlace: "Esta clase no se puede heredar." – kristian

+0

También podría devolver una Tuple de

Cuestiones relacionadas