2011-12-14 10 views
5

Supponiamo di voler ereditare da System.Data.SqlClient.SqlTransaction che è sigillato. Supere Voglio solo inserire un wrapper attorno allo SqlTransaction e utilizzare sempre MyTransaction anziché SqlTransaction. C'è un modo in cui potrei potenzialmente trasmettere MyTransaction a SqlTransaction utilizzando un operatore Implicito/Ampliamento?C'è un modo per ereditare FAKE in C#/VB.NET?

+5

'Supponiamo che io voglio ereditare da System.Data.SqlClient.SqlTransaction' => perché si vuole fare qualcosa di simile? –

+4

Darin ha ragione; stai chiedendo un trapano piuttosto che dirci perché hai bisogno di un buco in quella trave d'acciaio, in primo luogo. Il fatto che il tipo sia sigillato è una grande bandiera rossa che dice che NON VOGLIO CHE tu sia EREDITARIO DA QUESTO. Perché stai cercando di lavorare contro i desideri del designer della classe? Hanno a cuore i tuoi migliori interessi. Spiega cosa vuoi veramente realizzare, perché ereditare da una classe chiusa non succederà. –

+1

Non è possibile annullare la cancellazione di una classe utilizzando la riflessione? –

risposta

3

Se davvero vuole conversione implicita (anche se io non lo consiglio, in quanto è un'idea orribile e un design orribile, IMO), si può fare qualcosa di simile:

class MyTransaction 
    { 
     private readonly SqlTransaction _transaction; 

     public MyTransaction(SqlConnection conn) 
     { 
      _transaction = conn.BeginTransaction(); 
     } 

     public SqlTransaction Transaction 
     { 
      get 
      { 
       return _transaction; 
      } 
     } 

     public static implicit operator SqlTransaction(MyTransaction t) 
     { 
      return t.Transaction; 
     } 
    } 
+0

Sfortunatamente questo è in VB.NET e il loro operatore di Widening non sembra funzionare come "implicito" di C# è quello che ho appena scoperto ma stavo pensando anche a questa rotta ... Anche se come hai detto tu non mi piace neanche ... – Denis

+0

@Denis si può provare a codificare la classe in C# e quindi utilizzare la DLL nell'app VB –

+1

@Denis Code in C#, usare Refelctor per disassemblare in VB e si vede la sintassi. – TomTom

6

È possibile creare una classe con una variabile di transazione interna e quindi esporre i metodi e le proprietà. Un po 'come questo:

public class MyTransaction 
{ 
    System.Data.SqlTransaction myTx = someConnection.CreateTransaction(); 

    public void CommitTransaction() : { 
     myTx.CommitTransaction() 
    } 
} 

Si potrebbe anche rendere ereditare da DbTransaction e poi riscrivere le procedure astratte e virtuali per utilizzare la variabile myTx interna, ma comincia a diventare un po' complessa per nessun motivo reale apparente ...

+1

Assolutamente! : -Þ Ma se l'uomo vuole concludere una transazione, ci può essere una ragione! –

+0

Solo perché vuole farlo, e anche se è possibile, non significa che dovrebbe. –

+0

@Ramhound Sono d'accordo, ma è comunque un buon modo per imparare altri casi più adatti dove una soluzione come questa è adatta –

3

Se si è solo interessati ad aggiungere metodi aggiuntivi a una classe, è possibile utilizzare i metodi di estensione. Ciò non ti darà accesso a nessuno stato interno, né ti permetterà di sovrascrivere i comportamenti, ma ti permetterà di aggiungere funzionalità limitate. Non sono a conoscenza di alcun modo di ereditare da una classe sigillata.

È possibile creare un vero oggetto wrapper come altri hanno menzionato, ma non sarà possibile utilizzarlo in modo polimorfico al posto dell'oggetto originale.

+0

Questo è in .NET 2.0 quindi nessun metodo di estensione ... Ma devo anche tenere traccia di roba da quando è stata creata così i metodi di estensione non funzioneranno comunque. – Denis

+0

Non che ciò sia importante a causa della cosa .net 2, ma i metodi di estensione possono tracciare dati di oggetti indipendenti usando un dizionario escluso dal primo parametro del metodo di estensione (l'oggetto che viene manipolato). Questo può offrire un insieme di dati "partizionato" che assomiglia allo stato interno ma che è memorizzato all'esterno dell'oggetto. I membri interni sono accessibili tramite riflessione, quindi puoi fare alcune cose interessanti a seconda di quanto "brutto" sei disposto a lasciare ottenere il codice. –

+0

Spero non ti dispiaccia, ma ho aggiunto un tag .net2.0 alla tua domanda in modo che altri sappiano che la versione del framework è limitata. –

0

È possibile definire la propria classe MyTransaction come wrapper su SqlTransaction. Mantieni un'istanza di SqlTransaction in un campo privato in MyTransaction. Il tuo wrapper non sarà compatibile con SqlTransaction, ma se implementi le stesse interfacce SqlTransaction implementate puoi ottenere un risultato molto vicino.

+0

Ho pensato che questo avrebbe funzionato anche se poi avevi qualcosa come SqlClient.SQLCommand.Transaction che vuole SqlTransaction, non IDbTransaction che davvero sux quindi ho bisogno di un modo per simulare questo che ha dato inizio a questa ricerca ... – Denis

1

No, non è possibile ereditare la propria classe personalizzata da SqlTransaction o fare in modo che questo venga simulato.

Tuttavia, se il contesto di ciò che si sta facendo consente di utilizzare un DbTransaction, è possibile ereditare la classe di transazione personalizzata da DbTransaction, avvolgendo un SqlTransaction all'interno con qualsiasi altra funzionalità richiesta.

+0

Ho pensato che questo avrebbe funzionato anche se poi avevi qualcosa come SqlClient.SQLCommand.Transaction che vuole SqlTransaction – Denis

+0

Sì , si entra in un intero ratsnest di oggetti avvolti ... è possibile utilizzare tutto il wrapper personalizzato dal namespace System.Data che avvolge le versioni SQL .... tutto dipende da quali sono i requisiti e dal motivo per cui si stanno messing con questi oggetti nel primo posto. Ci sono probabilmente altri (migliori) modi per raggiungere l'obiettivo. –

1

Fate avere un'altra opzione, è possibile utilizzare Reflection.Emit() per aggiungere un'interfaccia di propria scelta a SqlTransaction e quindi utilizzare la stessa interfaccia nella nuova classe MyTransaction e quindi è possibile effettuare chiamate all'interfaccia, anziché alla classe.

Assicurarsi che questo funzioni solo all'interno delle librerie create dall'utente, oppure modificare in modo specifico i tipi caricati utilizzando Reflection.

+1

Inoltre, questa è una soluzione particolarmente sporca ... –

+0

Non ho mai provato Reflection.Emit(). Mi guarderò intorno ma hai qualche buon esempio/tutorial su come funzionerebbe? – Denis

1

È possibile creare metodi di estensione.

public static class SqlTransactionExtensions 
{ 
    public static void DoSomething(this SqlTransaction transaction, int myParameter) 
    { 
     // do something here 
    } 
} 

La classe deve essere statica. Posiziona la parola magica this davanti al parametro pugno che deve essere del tipo della classe che stai estendendo. È anche possibile estendere le interfacce. Se si desidera utilizzare questo metodo di estensione, è necessario disporre di uno using namspace con lo spazio dei nomi di questa classe di estensione, se non è definito nello stesso spazio dei nomi in cui si sta lavorando.

È quindi possibile chiamare il metodo di estensione, come se fosse un metodo regolare di SqlTransaction:

SqlTransaction t = new SqlTransaction(); 
t.DoSomething(5); 
+0

Questa è una buona idea proposta da qualcuno anche qui, ma ci sono 2 problemi con questo: (1) Sto usando .NET 2.0 e (2) Se non stavo usando .NET 2.0, come avrei usato i metodi di estensione per creare oggetti a creazione di SqlTransaction? (diciamo che voglio tenere traccia di chi ha creato questo sqlTransaction o l'ora in cui è stato avviato) – Denis

+0

Vorrei creare una classe helper statica per le transazioni. Molto simile alla classe estensioni, ma senza la parola chiave 'this'. Invece di chiamare i metodi con 't.DoSomething (5);', dovrai chiamarli con 'TransactionsHelper.DoSomething (t, 5);'. I metodi di estensione sono in realtà solo zucchero sintattico e non possono fare nulla che non possa essere fatto con i metodi normali. –

2

OK, in modo da escludere l'eredità e concentrandosi sul compito che si vuole veramente risolvere (sulla base del commento thread).

Ho avuto successo in passato eseguendo tutte le chiamate attraverso una libreria di supporto e implementando la logica lì. In passato, ho usato SqlHelper, che è pubblicato in Microsoft Data Application Block. Questo è un modulo sorgente, che puoi adattare alle tue esigenze. È possibile aggiungere qualsiasi registrazione o altra logica richiesta.

Rende anche il codice molto leggibile. Si possono fare cose come:

SqlHelper.ExecuteDataset() per le query che ritornano insiemi di dati,

SqlHelper.ExecuteScalar() per le query di restituzione di valori singoli,

SqlHelper.ExecuteNonQuery() per i comandi che non hanno rendimenti (come INSERT 's).

ecc

Problemi correlati