2016-09-09 4 views
1

Мне интересно, если я собираюсь сделать это неправильно. Я начинаю входить в классы и пытаюсь использовать их больше в моем коде VBA.Класс, возвращающий (частный?) Диапазон

Я создал код, который импортирует CSV-файл на вновь созданный рабочий лист. Я создаю рабочий лист внутри класса и импортирую его в некоторый диапазон. Диапазон варьируется в зависимости от импортируемого файла. В идеале я хотел бы вернуть ссылку диапазона на мой модуль за пределами класса и циклически перемещаться по диапазону, как мне было нужно.

Не могу показаться, что я не могу вернуть объект диапазона с кодом модуля. с:

' Module code '''' \/ 
set NewTest as new TestClass 
Dim testrange As Range 
test Range = NewTest.SourceRange 
' Module code '''' /\ 




Option Explicit 

Const cDirectory As String = "C:\directory" 'file path 
Const cFileExt As String = ".CSV" 'file 

Const cSourceCode As String = "wsSourceCode" 


Private cFinalFileName As String 
Private wsSourceCode As Worksheet 
Private cSourcePath As String 
Private pSourceRange As Range 
Private LastRow As Integer 
Private pSourceSheet As String 


'''''''''''''''''''''''''''''''''''''''''''''''''''' Can i do this !?!?!?!? \/ 
Public Property Get SourceRange() As Range 
    LastRow = wsSourceCode.Cells(wsSourceCode.Rows.Count, "A").End(xlUp).Row 
    Set pSourceRange = wsSourceCode.Range("A1:A" & LastRow) 
    SourceRange = pSourceRange 
End Property 
'''''''''''''''''''''''''''''''''''''''''''''''''''' Can i do this !?!?!?!? ?| 



Public Property Get SourceSheet() As String 
    pSourceSheet = wsSourceCode.Name 
    SourceSheet = pSourceSheet 
End Property 




Public Property Get FinalRange() As String 
    FinalRange = pFinalRange 
End Property 

Public Property Set FinalRange(Value As Range) 
    pFinalRange = Value 
End Property 

Public Property Let SourceFile(Value As String) 
    pSourceFile = Value 
    cFinalFileName = pSourceFile & "Production" & cFileExt 
    cSourcePath = cDirectory & pSourceFile & cFileExt 
End Property 



Private Sub Class_Initialize() 
    'Create Holding Sheet to Populate and augment Code 
    Application.DisplayAlerts = False 
    On Error Resume Next 
    ThisWorkbook.Sheets(cSourceCode).Delete 
    On Error GoTo 0 
    Application.DisplayAlerts = True 
    ActiveWorkbook.Worksheets.Add(After:=Worksheets(1)).Name = cSourceCode 
    Set wsSourceCode = Sheets(cSourceCode) 
    'WsHolding.Visible = False 
End Sub 


Private Sub Class_Terminate() 
' Application.DisplayAlerts = False 
' On Error Resume Next 
' ThisWorkbook.Sheets(cSourceCode).Delete 
' On Error GoTo 0 
' Application.DisplayAlerts = True 
End Sub 



Public Sub ExportCode(ByVal pFinalRange As Range) 
'''''''''''''''''''''''''''''''''''''''''''''''''''' 
'This Process Will import the final Range of output 
'code and export it to a Output file. 
' The Output file was delare earlier. 
' 
' 
'''''''''''''''''''''''''''''''''''''''''''''''''''' 
Dim fso As Object 
Dim Fileout As Object 
Dim myFile As String 
Dim rng As Range 
myFile = cOutputFile 
Open myFile For Output As #1 
For Each rng In pFinalRange 
    Print #1, rng 
Next rng 
Close 1 

End Sub 


Public Sub ImportFile(ByVal cSourceFileName As String) 
'''''''''''''''''''''''''''''''''''''''''''''''''''' 
'This Process Will import the final Range of output 
'code and export it to a Output file. 
' The Output file was delare earlier. 
' 
' 
'''''''''''''''''''''''''''''''''''''''''''''''''''' 
Dim strTextLine As String 
Dim cSourcePath As String 
cSourcePath = cDirectory & cSourceFileName & cFileExt 
Dim iFile As Integer: iFile = FreeFile 
Dim i As Integer: i = 1 
Open cSourcePath For Input As #iFile 'open the file 
Do Until EOF(1) 'until the end of the file 
    Line Input #1, strTextLine 'set each line equal to variable strTextLine 
    wsSourceCode.Cells(i, 1).NumberFormat = "@" 
    wsSourceCode.Cells(i, 1) = CStr(strTextLine) 
    i = i + 1 
Loop 
Close #iFile 



End Sub 
+1

«Диапазон» - это объект, поэтому вам нужно использовать ключевое слово 'Set' везде, где вы его назначаете. – Comintern

ответ

5

Короткий ответ в основном what @Comintern said.

Это:

SourceRange = pSourceRange 

Должно быть так:

Set SourceRange = pSourceRange 

Я побежал последним Rubberduck «s код проверки на вашем классе, и моя маленькая уточка (я управляю, что с открытым исходным кодом проекта) соглашается:

объект переменной„SourceRange“присваивается без„Set“ ключевое слово

Насколько Rubberduck может сказать, эта переменная является переменной объекта, назначенной без ключевого слова «Установить». Это вызывает ошибку времени выполнения 91 'Объект или с заблокированной переменной блока.

Так вы спрашиваете, Могу ли я это сделать?

Конечно, вы можете - реальный вопрос, следует ли .

У вас есть Property Get процедуру , которая имеет побочные эффекты и может поднять ошибку времени выполнения если звезды выровнены. Это не хорошо.

Property Get процедура должна иметь предсказуемое и воспроизводимое поведение - это не должно быть установки ничего в внутреннем состоянии класса, а быть возвращением значения, это инкапсулированное в этом внутреннем, частного состоянии.

Найдите минутку, чтобы прочитать .net property design guidelines - все это является также применимо к конструкции недвижимости VBA (только заменить «бросать исключения» с «поднимая ошибок»).

Так лучшеSourceRange свойство будет выглядеть примерно так:

Public Property Get SourceRange() As Range 
    If wsSourceCode Is Nothing Then Exit Property 
    Dim lastRow As Long 
    lastRow = = wsSourceCode.Cells(wsSourceCode.Rows.Count, "A").End(xlUp).Row 
    Set SourceRange = wsSourceCode.Range("A1:A" & LastRow) 
End Property 

Обратите внимание, что только для чтения (получить только) недвижимость стоит самостоятельно, прицелы свои собственные локальные переменные, не мутируют внутреннего state, возвращает Nothing, если ссылка wsSourceCode не установлена, и не предполагает, что рабочий лист имеет менее 32 767 строк (это максимальное значение для переменной Integer).

Что не нужно Нужно жить на уровне модуля, должно жить на уровне процедуры: держать переменные области как можно меньше.


Если бы это было Code Review ответ, который я бы также сказать, что Class_Initialize обработчик делает слишком много, не так легко предсказуемые вещи - рассмотреть этот случай использования; как foo и bar любой другой?

Set foo = New TestClass 
Set bar = New TestClass 

'this goes boom. why? 
Debug.Print foo.SourceRange.Address, bar.SourceRange.Address 

К сожалению, ну я все равно сказал.

Смежные вопросы