Class Scoping Confusion

G

Grok

In writing a class library, one of the classes should only ever be
instantiated once, and its object should be accessible to every other
class in the library. How can I do that?

To provide some actual names for discussion, I'm trying to do this
with a custom log-writing class, named LogWriter.vb. So I would like
to declare ..

Class library project:
LogWriter.vb
Drives.vb
Folders.vb
Files.vb

Friend Logger As LogWriter = new LogWriter(LogFilename)

and have Drivers, Folders, and Files classes all be able to use the
sole instantiation "Logger" in their code.

Hints on how to organize this properly?
 
P

Phill W.

Grok said:
In writing a class library, one of the classes should only ever be
instantiated once, and its object should be accessible to every other
class in the library. How can I do that?
To provide some actual names for discussion, I'm trying to do this
with a custom log-writing class, named LogWriter.vb. So I would like
to declare ..

Class library project:
LogWriter.vb
Drives.vb
Folders.vb
Files.vb

Friend Logger As LogWriter = new LogWriter(LogFilename)

and have Drivers, Folders, and Files classes all be able to use the
sole instantiation "Logger" in their code.

Hints on how to organize this properly?

Properly? Don't know, but here's how I'd throw it together:

Public Class LogWriter
Public ReadOnly Property Drives() as Drives
Get
Return New Drives( Me )
End Get
End Property
End Class

Public Class Drives
Private Sub New()
End Sub

Friend Sub New( ByVal parent as LogWriter )
m_parent = parent
End Sub

Private m_parent as LogWriter = Nothing

Private ReadOnly Property Parent() as LogWriter
Get
return m_parent
End Get
End Property

End Class

Note the accessors on the Classes and Constructors.

Anyone "out there" can create an instance of LogWriter - it's
constructor is Public. They can't, however, create an instance of
Drives /directly/ - it's constructor is only accessible /inside/ your
library [assembly].

To get one, they have to use the Drives property on the LogWriter class,
which means that your code gets a look in and can deal with linking the
two objects together.
Of course, the Drives property doesn't /have/ to be Public...

HTH,
Phill W.
 
C

Cor Ligthert[MVP]

Grok,

Normally it is just setting a reference to your library (dll).
This can using project or by right clicking on the reference tab in your
solution explorer

Cor
 
F

Family Tree Mike

Grok said:
In writing a class library, one of the classes should only ever be
instantiated once, and its object should be accessible to every other
class in the library. How can I do that?

To provide some actual names for discussion, I'm trying to do this
with a custom log-writing class, named LogWriter.vb. So I would like
to declare ..

Class library project:
LogWriter.vb
Drives.vb
Folders.vb
Files.vb

Friend Logger As LogWriter = new LogWriter(LogFilename)

and have Drivers, Folders, and Files classes all be able to use the
sole instantiation "Logger" in their code.

Hints on how to organize this properly?

I think your subject through the others off the track. You seem to want to
create a singleton class. One way that I use is to create a private
constructor, and public shared instance method. The instance method checks
to see if a copy exists.

public class Logger
private mLogger as Logger = Nothing

private property Instance as Logger
get
if (mLogger is Nothing) then
mLogger = new Logger()
endif
return mLogger
end get
end property

private sub New()
end sub
end class
 
F

Family Tree Mike

public class Logger
private mLogger as Logger = Nothing

private property Instance as Logger
get
if (mLogger is Nothing) then
mLogger = new Logger()
endif
return mLogger
end get
end property

private sub New()
end sub
end class

Sorry, temporary insanity, and typing off the IDE. The Instance property
should be public, not private...
 
F

Family Tree Mike

Phill W. said:
Grok said:
In writing a class library, one of the classes should only ever be
instantiated once, and its object should be accessible to every other
class in the library. How can I do that?
To provide some actual names for discussion, I'm trying to do this
with a custom log-writing class, named LogWriter.vb. So I would like
to declare ..

Class library project:
LogWriter.vb
Drives.vb
Folders.vb
Files.vb

Friend Logger As LogWriter = new LogWriter(LogFilename)

and have Drivers, Folders, and Files classes all be able to use the
sole instantiation "Logger" in their code.

Hints on how to organize this properly?

Properly? Don't know, but here's how I'd throw it together:

Public Class LogWriter
Public ReadOnly Property Drives() as Drives
Get
Return New Drives( Me )
End Get
End Property
End Class

Public Class Drives
Private Sub New()
End Sub

Friend Sub New( ByVal parent as LogWriter )
m_parent = parent
End Sub

Private m_parent as LogWriter = Nothing

Private ReadOnly Property Parent() as LogWriter
Get
return m_parent
End Get
End Property

End Class

Note the accessors on the Classes and Constructors.

Anyone "out there" can create an instance of LogWriter - it's
constructor is Public. They can't, however, create an instance of
Drives /directly/ - it's constructor is only accessible /inside/ your
library [assembly].

To get one, they have to use the Drives property on the LogWriter class,
which means that your code gets a look in and can deal with linking the
two objects together.
Of course, the Drives property doesn't /have/ to be Public...

HTH,
Phill W.

Sorry Phill. I missed this when I posted... I didn't copy your paper!
 
G

Grok

Thanks for the replies. Yes, I described the question poorly. It is
solved now. Here is the completed, working solution and test code.

Family Tree Mike, I was not grasping how to use the Instance property
as you intended, so was getting two LogWriter objects instead of one.

All your solution needed was the Shared keyword.

===== Implementation =====
'file: LogWriter.vb
Imports System.IO
Namespace GrokQuestion
'file: LogWriter.vb
'singleton to write logfile; used by public classes
Friend Class LogWriter
Shared mLogWriter As LogWriter = Nothing
Shared _filename As String
Friend Sub New()
End Sub
Shared ReadOnly Property Instance() As LogWriter
Get
Console.WriteLine("Get Instance() called.")
If (mLogWriter Is Nothing) Then
mLogWriter = New LogWriter()
End If
Console.WriteLine("Old Filename = """ + _filename +
"""")
Return mLogWriter
End Get
End Property
Public Property Filename() As String
Get
Return _filename
End Get
Set(ByVal value As String)
_filename = value
End Set
End Property
Public Sub WriteLine(ByVal Message As String)
'open file, write Message, close file
Console.WriteLine(" Message = """ + Message + """")
Dim sw As System.IO.StreamWriter = New
System.IO.StreamWriter(_filename)
sw.WriteLine(Message)
sw.Close()
End Sub
End Class
End Namespace

'file: Folders.vb
Namespace GrokQuestion
'file: Folders.vb
Public Class Folders
Private Logger As LogWriter
Public Sub New(ByVal LogFilename As String)
Logger = LogWriter.Instance()
Logger.Filename = LogFilename
Logger.WriteLine("Folders class online!")
End Sub
End Class
End Namespace

'file: Files.vb
Namespace GrokQuestion
'file: Files.vb
Public Class Files
Private Logger As LogWriter
Public Sub New(ByVal LogFilename As String)
Logger = LogWriter.Instance()
Logger.Filename = LogFilename
Logger.WriteLine("Files class online!")
End Sub
End Class
End Namespace

===== Test =====
Imports GrokQuestion

Module Module1

Sub Main()
TestFiles()
TestFolders()
End Sub

Private Sub TestFiles()
Console.WriteLine("TestFiles() .. expecting old filename =
""""" + vbCrLf)
Dim LogFilename As String = "C:\TEMP\First.txt"
Dim pFiles As GrokQuestion.GrokQuestion.Files = New
GrokQuestion.GrokQuestion.Files(LogFilename)
Console.WriteLine()
End Sub

Private Sub TestFolders()
Console.WriteLine("TestFolders() .. expecting old filename =
""C:\Test\First.txt""" + vbCrLf)
Dim LogFilename As String = "C:\TEMP\Second.txt"
Dim pFolders As GrokQuestion.GrokQuestion.Folders = New
GrokQuestion.GrokQuestion.Folders(LogFilename)
Console.WriteLine()
End Sub

End Module

===== Test Output =====
TestFiles() .. expecting old filename = ""

Get Instance() called.
Old Filename = ""
Message = "Files class online!"

TestFolders() .. expecting old filename = "C:\Test\First.txt"

Get Instance() called.
Old Filename = "C:\TEMP\First.txt"
Message = "Folders class online!"

--end
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top