2010-01-05 10 views
6

Ho un semplice problema.Involucro di una classe non ereditabile in C#

Desidero decorare la classe SqlDataReader in modo che quando vengono chiamati i metodi di eliminazione o chiusura, posso disporre di una risorsa nascosta allo stesso tempo.

la classe SqlDataReader non è ereditabile.

Come posso realizzare questo? Non voglio davvero implementare DbDataReader, IDataReader, IDisposable & interfacce IDataRecord

+0

Cosa intendi per non ereditabile? È una lezione sigillata? Vuoi approfondire le interfacce? Non DEVI implementare quelli? Inoltre, perché NON vuoi? –

+0

SqlDataReader non è sigillato, quindi è ereditabile, ma i suoi costruttori sono privati, quindi non puoi soddisfare il costruttore di base quando ne erediti: sto solo facendo il pignolo sui dettagli, ma hai ragione. –

+0

Oltre al mio commento sulla risposta di silky, non posso fare a meno di chiedermi ... cosa potresti aver bisogno di impacchettare con un 'SqlDataReader'? Spero davvero che non sia un 'SqlCommand' o' SqlConnection' ... – Aaronaught

risposta

5

Anche se è possibile ereditare da SqlDataReader, non importa comunque perché non è possibile creare in SqlCommand un'istanza della classe derivata.

L'implementazione di IDataReader in un wrapper non è affatto difficile quando si rimanda al SqlDataReader sottostante. È solo un po 'di tempo, ma non così male.

Ma io sono curioso, è la risorsa che si desidera disporre la connessione? In tal caso, esiste un membro CloseConnection dell'enumerazione CommandBehavior che garantisce che la connessione venga chiusa quando il lettore di dati viene chiuso.

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

Si noti che Chiudi/Disponi sono la stessa cosa su SqlDataReader.

Infine, ecco un ultimo suggerimento che mi ha servito bene in passato. Si noti che nell'esempio successivo che segue, si possiede SqlDataReader dall'inizio alla fine anche se si sta "cedendo" al chiamante su ciascun record.

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

La risorsa è un ticket monouso che viene utilizzato per proteggere l'accesso al database SQL –

+0

OK. Ho aggiunto un altro suggerimento nella mia risposta che potrebbe essere di aiuto. – Josh

+0

Questa è una soluzione molto interessante. Quali sono le opinioni delle persone su questo? –

3

Inverso; usa la tua risorsa "nascosta" come la cosa principale, implementa IDisposable e poi chiudi DataReader quando hai finito.

+0

Preferirei che il codice chiamante non ne sapesse nulla. Al momento è in attesa di un'istanza di SqlDataReader –

+4

Possiedi il codice chiamante? Ha davvero bisogno di accettare un 'SqlDataReader'? È qualcosa che dovresti cercare di non passare in giro; se riesci a far sì che accetti un 'IDataReader', puoi ricomporre 'SqlDataReader' piuttosto facilmente. – Aaronaught

+0

Sì, possiedo il codice chiamante. Preferirei non dover avvolgere la classe (implementare IDataReader) –

1

http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.aspx La classe non è sigillata. Dovresti solo essere in grado di chiamare base.dispose() all'inizio della sovrascrittura e quindi inserire il tuo codice dopo.

io non sono il mio IDE di fronte a me ma dovrebbe guardare somthing come

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. 
    } 
} 

EDIT --- basta leggere i commenti originale, vedo che ha il costruttore privato, mi permetta di scoppiare il mio VS2008 e mal BRB

guardando dentro ad esso, e tutti cercano queste soluzioni di fantasia, l'unica cosa che vedo che può essere fatto è

public class myClass : IDisposable 
{ 

    public SqlDataReader dataReader { get; set; } 

    #region IDisposable Members 

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

    #endregion 
} 

EDIT --- Sigh, questo è esattamente ciò che Silky ha pubblicato 40 minuti fa.

+0

Questo codice causa ERRORI COMPILATI: Errore # 1 Il tipo 'System.Data.SqlClient.SqlDataReader' non ha costruttori definiti ... e ... Errore # 2 'System.Data.SqlClient.SqlDataReader.SqlDataReader (System.Data.SqlClient.SqlCommand, System.Data.CommandBehavior)' non è accessibile a causa del livello di protezione –

+0

prima riga del collegamento: "Questa classe non può essere ereditata." – kristian

+0

Potrebbe anche restituire una tupla di

Problemi correlati