2013-03-20 45 views
0

我想從NHibernate的SqlClientBatchingBatcher類繼承的正是這樣(從TooManyRowsAffectedException with encrypted triggers採取代碼):如何在override中訪問超類的私有成員?

public class NonBatchingBatcherWithoutVerification : SqlClientBatchingBatcher 
{ 
    public NonBatchingBatcherWithoutVerification(ConnectionManager connectionManager, IInterceptor interceptor) : base(connectionManager, interceptor) 
    {} 

    protected override void DoExecuteBatch(IDbCommand ps) 
    { 
     log.DebugFormat("Executing batch"); 
     CheckReaders(); 
     Prepare(currentBatch.BatchCommand); 
     if (Factory.Settings.SqlStatementLogger.IsDebugEnabled) 
     { 
      Factory.Settings.SqlStatementLogger.LogBatchCommand(currentBatchCommandsLog.ToString()); 
      currentBatchCommandsLog = new StringBuilder().AppendLine("Batch commands:"); 
     } 

     int rowsAffected = currentBatch.ExecuteNonQuery(); 

     // Removed the following line 
     //Expectations.VerifyOutcomeBatched(totalExpectedRowsAffected, rowsAffected); 

     currentBatch.Dispose(); 
     totalExpectedRowsAffected = 0; 
     currentBatch = new SqlClientSqlCommandSet(); 
    } 
} 

只是發現一些在法訪問這裏(如currentBatch中或totalExpectedRowsAffected)成員。

那麼,事實證明,這些成員實際上是私有的在當前的NHibernate 3.3源的超類。那麼如何在不復制整個事物的情況下有效地繼承這個類?這是該類未修改的NHibernate代碼:

public class SqlClientBatchingBatcher : AbstractBatcher 
{ 
    private int _batchSize; 
    private int _totalExpectedRowsAffected; 
    private SqlClientSqlCommandSet _currentBatch; 
    private StringBuilder _currentBatchCommandsLog; 
    private readonly int _defaultTimeout; 

    public SqlClientBatchingBatcher(ConnectionManager connectionManager, IInterceptor interceptor) 
     : base(connectionManager, interceptor) 
    { 
     _batchSize = Factory.Settings.AdoBatchSize; 
     _defaultTimeout = PropertiesHelper.GetInt32(Cfg.Environment.CommandTimeout, Cfg.Environment.Properties, -1); 

     _currentBatch = CreateConfiguredBatch(); 
     //we always create this, because we need to deal with a scenario in which 
     //the user change the logging configuration at runtime. Trying to put this 
     //behind an if(log.IsDebugEnabled) will cause a null reference exception 
     //at that point. 
     _currentBatchCommandsLog = new StringBuilder().AppendLine("Batch commands:"); 
    } 

    public override int BatchSize 
    { 
     get { return _batchSize; } 
     set { _batchSize = value; } 
    } 

    protected override int CountOfStatementsInCurrentBatch 
    { 
     get { return _currentBatch.CountOfCommands; } 
    } 

    public override void AddToBatch(IExpectation expectation) 
    { 
     _totalExpectedRowsAffected += expectation.ExpectedRowCount; 
     IDbCommand batchUpdate = CurrentCommand; 
     Driver.AdjustCommand(batchUpdate); 
     string lineWithParameters = null; 
     var sqlStatementLogger = Factory.Settings.SqlStatementLogger; 
     if (sqlStatementLogger.IsDebugEnabled || Log.IsDebugEnabled) 
     { 
      lineWithParameters = sqlStatementLogger.GetCommandLineWithParameters(batchUpdate); 
      var formatStyle = sqlStatementLogger.DetermineActualStyle(FormatStyle.Basic); 
      lineWithParameters = formatStyle.Formatter.Format(lineWithParameters); 
      _currentBatchCommandsLog.Append("command ") 
       .Append(_currentBatch.CountOfCommands) 
       .Append(":") 
       .AppendLine(lineWithParameters); 
     } 
     if (Log.IsDebugEnabled) 
     { 
      Log.Debug("Adding to batch:" + lineWithParameters); 
     } 
     _currentBatch.Append((System.Data.SqlClient.SqlCommand) batchUpdate); 

     if (_currentBatch.CountOfCommands >= _batchSize) 
     { 
      ExecuteBatchWithTiming(batchUpdate); 
     } 
    } 

    protected override void DoExecuteBatch(IDbCommand ps) 
    { 
     Log.DebugFormat("Executing batch"); 
     CheckReaders(); 
     Prepare(_currentBatch.BatchCommand); 
     if (Factory.Settings.SqlStatementLogger.IsDebugEnabled) 
     { 
      Factory.Settings.SqlStatementLogger.LogBatchCommand(_currentBatchCommandsLog.ToString()); 
      _currentBatchCommandsLog = new StringBuilder().AppendLine("Batch commands:"); 
     } 

     int rowsAffected; 
     try 
     { 
      rowsAffected = _currentBatch.ExecuteNonQuery(); 
     } 
     catch (DbException e) 
     { 
      throw ADOExceptionHelper.Convert(Factory.SQLExceptionConverter, e, "could not execute batch command."); 
     } 

     Expectations.VerifyOutcomeBatched(_totalExpectedRowsAffected, rowsAffected); 

     _currentBatch.Dispose(); 
     _totalExpectedRowsAffected = 0; 
     _currentBatch = CreateConfiguredBatch(); 
    } 

    private SqlClientSqlCommandSet CreateConfiguredBatch() 
    { 
     var result = new SqlClientSqlCommandSet(); 
     if (_defaultTimeout > 0) 
     { 
      try 
      { 
       result.CommandTimeout = _defaultTimeout; 
      } 
      catch (Exception e) 
      { 
       if (Log.IsWarnEnabled) 
       { 
        Log.Warn(e.ToString()); 
       } 
      } 
     } 

     return result; 
    } 
} 

我忽略了什麼嗎?似乎是一個相當糟糕的方法來複制整個事情,只是爲了覆蓋所有私人成員的訪問權限。我只想重寫一種方法!

回答

4

如果它們被設置爲私人的,那麼你可以做的事情真的沒有(使用反射,這是醜陋的,當然不總是安全的)。

1

Private超類的成員無法訪問,因爲它們是private。封裝在OOP中是爲了禁止這個直接訪問,所以確保對象正常工作。
可能有properties訪問私有成員,這些是您可以用來讀寫私人成員的私鑰。這些屬性將確保不會對對象造成傷害。

+0

爲什麼你不要使用使用私人支持變量的屬性? – Blorgbeard 2013-03-20 20:51:26

+0

我表達了自己的一點不清楚,現在會改變... – 2013-03-20 20:52:16

1

您可以訪問私有字段,屬性和使用反射父類的方法(例如,訪問一個字段說明如下:Reflecting a private field from a base class

這不是安全的,但是作爲私人的想法是,庫的實現可能會改變,那些私有方法,字段和屬性可能會改變或消失。如果他們更改實施,更新可能會破壞您的代碼。

這就是說,我自己做了幾次。你只需要權衡風險。

11

只有一個合法訪問基類的私有成員的方法:把派生類的基類中:

class Base 
{ 
    private int x; 
    private class Derived : Base 
    { 
     private void M() 
     { 
      Console.WriteLine(this.x); // legal! 
     } 
    } 
} 

當然,如果你可以把類的基類中,那麼你也可以重寫基類,以便成員受到保護。

原始作者將這些成員設爲私人對您而言是暗示該課程並非專門爲您設計的。