2010-01-05 15 views
6

Ich habe ein einfaches Problem.Wrapping einer nicht vererbbaren Klasse in C#

Ich möchte die SqlDataReader-Klasse so dekorieren, dass beim Aufruf der Methoden "dispose" oder "close" eine versteckte Ressource zur gleichen Zeit verfügbar ist.

Die SqlDataReader-Klasse ist nicht vererbbar.

Wie kann ich das erreichen? Ich möchte wirklich nicht den DbDataReader, IDataReader, IDisposable implementieren & IDataRecord Schnittstellen

+0

Was meinen Sie nicht vererbbar? Ist es eine versiegelte Klasse? Würden Sie die Schnittstellen näher erläutern? Müssen Sie diese nicht umsetzen? Auch, warum willst du nicht? –

+0

SqlDataReader ist nicht versiegelt, so dass es vererbbar ist, aber seine Konstruktoren sind privat, so dass Sie den Basiskonstruktor nicht erfüllen können, wenn Sie davon erben - ich bin nur pingelig über Details, aber Sie haben Recht. –

+0

Zusätzlich zu meinem Kommentar zu silkys Antwort kann ich mich nicht wundern ... was könnte man brauchen, um mit einem 'SqlDataReader' zu verpacken? Ich hoffe wirklich, dass es kein 'SqlCommand' oder' SqlConnection' ist ... – Aaronaught

Antwort

5

Selbst wenn Sie von SqlDataReader erben könnten, wäre das egal, weil Sie SqlCommand nicht dazu bringen könnten, eine Instanz Ihrer abgeleiteten Klasse zu erstellen.

Die Implementierung von IDataReader in einem Wrapper ist wirklich nicht schwierig, wenn Sie nur auf den zugrunde liegenden SqlDataReader verzichten. Es ist nur ein bisschen zeitaufwendig, aber nicht so schlimm.

Aber ich bin neugierig, ist die Ressource, die Sie möchten, die Verbindung entsorgt? Wenn dies der Fall ist, gibt es ein CloseConnection-Mitglied der CommandBehavior-Enumeration, das sicherstellt, dass die Verbindung geschlossen wird, wenn der Datenleser geschlossen wird.

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

Beachten Sie, dass Close/Dispose auf SqlDataReader die gleiche Sache sind.

Endlich, hier ist ein letzter Vorschlag, der mir in der Vergangenheit gut gedient hat. Beachten Sie, dass Sie im folgenden lockeren Beispiel den SqlDataReader vom Anfang bis zum Ende besitzen, obwohl Sie bei jedem Datensatz dem Aufrufer "nachgeben".

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

Die Ressource ist ein Einwegticket, das verwendet wird, um den Zugriff auf die SQL-Datenbank zu schützen –

+0

Okay, ich habe einen weiteren Vorschlag in meiner Antwort hinzugefügt, der helfen könnte. – Josh

+0

Das ist eine sehr interessante Lösung. Was denken die Leute dazu? –

3

Reverse it; Verwenden Sie Ihre "versteckte" Ressource als Hauptsache, implementieren Sie IDisposable, und schließen Sie dann den DataReader, wenn Sie damit fertig sind.

+0

würde mir wirklich lieber den rufcode nicht auswaschen. Es erwartet derzeit eine Instanz von SqlDataReader –

+4

Besitzen Sie den aufrufenden Code? Muss wirklich ein 'SqlDataReader' akzeptiert werden? Das solltest du versuchen, nicht herumzugehen; Wenn Sie dafür sorgen können, dass ein IDataReader akzeptiert wird, können Sie 'SqlDataReader' einfach umbrechen. – Aaronaught

+0

Ja, ich besitze den Telefoncode. Ich möchte die Klasse lieber nicht umhüllen (implementieren IDataReader) –

1

http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.aspx Die Klasse ist nicht versiegelt. Sie sollten einfach in der Lage sein, base.dispose() am Anfang Ihrer Überschreibung aufzurufen und dann Ihren Code danach zu setzen.

ich nicht meine IDE vor mir haben, aber es sollte Somthing aussehen

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 --- nur die ursprünglichen Kommentare lesen, ich sehe, dass es den privaten Konstruktor hat, lassen Sie mich ausbrechen mein VS2008 und krank brb

in ihm suchen, und jeder ist diese Phantasie Lösungen versucht, das einzige, was ich sehen kann getan werden, ist

public class myClass : IDisposable 
{ 

    public SqlDataReader dataReader { get; set; } 

    #region IDisposable Members 

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

    #endregion 
} 

EDIT --- Seufz, das ist genau das, was Silky vor 40 Minuten gepostet hat.

+0

Dieser Code verursacht die COMPILE ERRORS: Fehler # 1 Der Typ 'System.Data.SqlClient.SqlDataReader' hat keine Konstruktoren definiert ... und ... Fehler # 2 Auf 'System.Data.SqlClient.SqlDataReader.SqlDataReader (System.Data.SqlClient.SqlCommand, System.Data.CommandBehavior)' kann aufgrund der Schutzstufe –

+0

der ersten Zeile Ihres Links nicht zugegriffen werden: "Diese Klasse kann nicht vererbt werden." – kristian

+0

Es kann auch ein Tuple von

Verwandte Themen