-----------------------------------------------------------
New Message on BDOTNET
-----------------------------------------------------------
From: SitaramanM
Message 8 in Discussion
Hi Thts quite and interesting problem. Have given two solutiions below, but thought
i might as well describe how i reached the solutions. a) I basically created a
singleton class as i wrote in my previous posr that is, with a private constructor and
a public Shared ReadOnly Object. Works fine in a normal mode b) Tried installing it in
COM+ c) As u said, i got an error, as We cannot use private contructor if it is to be
installed in COM+ d) I made the constructor public e) But now the prob is that the
outside world can instantiate this object as the constructor is public. But This
should not be the case in a singlton right f) So in the public constructor, i just
threw a NotSupported Exception like this <Transaction(TransactionOption.Required)>
Public Class Numbering
Inherits ServicedComponent Public Shared ReadOnly Instance As Numbering = New
Numbering
Public Sub New()
Throw New NotSupportedException("Direct Instantiation Not Supported. Use
Instance method to get an Instance of this class")
End Sub g) Was a stupid attempt as, Now if someone instantiates the object of this
class then he will get an exception , which is fine and required, but at the same
time even if the Shared member variable is internally initialized then it will throw
exception only h) tried to be smart and made a patch. Added a private constructor
which takes an int as parameter and then initialized my Shared Reradonly Instance
variable with that constructor by passing a int parameter. Outside world will use the
public constructor and get an exception, but i will be able to internally initialize
it with the overloaded constructor. Code is as follows
<Transaction(TransactionOption.Required)> Public Class Numbering
Inherits ServicedComponent Public Shared ReadOnly Instance As Numbering = New
Numbering(1)
Public Sub New()
Throw New NotSupportedException("Direct Instantiation Not Supported. Use
Instance method to get an Instance of this class")
End Sub Private sub New(p_intDummy as integer) 'Dummy end sub i)
MS turned out to be smarter. Got a runtime exception saying that Serviced Components
cannot have parameterized constructor calls :( Solution 1 Took a couple of minutes
and thought it over. Basically the key is the way the Shared variables are
initialized. In .Net when u declare a Shared member variable, the compiler adds a
Type Initializer(also called Type Constructor or Class Constructor, is compiled to a
function called .cctor). The runtime will call this Class Constructor internally. When
it is called varied, but one thing is that it will DEFINITELY be called before the
variable is used. This is the key here. So if a cll to initialize the object is
issued, first the .cctor(class constructor) WILL be called which will initialize th
Shared Variable. Only then is the .ctor(Constructor/public sub New) will be called.
So a small trick as below will do the job Public Sub New()
If Not Instance Is Nothing Then
Throw New NotSupportedException("Direct Instantiation Not Supported. Use
Instance method to get an Instance of this class")
End If
End Sub ;). Note that the client issues a call to instantiate the object.
Runtime will supersede it and instead of calling New it will call the .cctor, which
will initialize the Instance variable. So my singleton is initialized. then it will
call the New(.ctor). In the New im, checking the Instance variable. As it is already
initialized it will throw the Not Supported Exception. So Noone can instantiate this
object and can access only the Shared Readonly variable, which is what u wanted :)
Soultion2 This is for the more adventrous ones. Note that afterStep h), my main
requirement is that the local Shared variable should be initialized, but any outside
call to initialize should be rejected. Right!!! So what i need to know in New is
that who is instantiating the object or to be precise, what is the method which
called the new. if new was called due to the local shared readonly variable
initialization then i should allow it else i should throw the exception. Right.
Enter StackFrame Class. In the New i traverse thru the calling function backwards and
keep checking whether the called function in the chain is .cctor. If so then i know
tht it is the type initializer which is initializing. Now I also need to know whether
it is the type initializer of this class only or not(as it is possible that you can
initialize the object from the type initializer of a different object of your own and
hack the code). This i find out by doing a DeclaringType ofthe .cctor method. If it
is the same as current class, then i can be SURE that this new resulted from the
Shared Readonly variable initialization,which is OK, so i do an exit sub. If i do not
get a .cctor in the method call chain (or) i do get a .cctor, but the declaring type
is different, then i throw the exception. Tricky byut works Public Sub New()
Dim iCtr As Integer = 1 While True Dim sf As StackFrame =
New StackFrame(iCtr)
Dim l_objCallingMethod As MethodBase = sf.GetMethod() If
l_objCallingMethod Is Nothing Then
Exit While
Else
If l_objCallingMethod.Name = ".cctor" Then
If l_objCallingMethod.DeclaringType.ToString = Me.GetType.ToString
Then
Exit Sub
End If
End If
End If
iCtr = iCtr + 1
End While
Throw New NotSupportedException("Direct Instantiation Not Supported. Use
Instance method to get an Instance of this class") Need to test more, but basically
you can circumvent the limitation of COM Server. So this is an approach tht u can
follow. The complete code for the Solution1(Numbering.vb) and
Solution2(Numbering2.vb) is as follows. Check it out and do get back in case of any
problems. Imports System.Diagnostics
Imports System.Reflection
Imports System.Threading
Imports System.EnterpriseServices <Transaction(TransactionOption.Required)> Public
Class Numbering
Inherits ServicedComponent Public Shared ReadOnly Instance As Numbering = New
Numbering
Private m_intCtr As Integer
Private m_objLockObject As New Object
Public Sub New()
If Not Instance Is Nothing Then
Throw New NotSupportedException("Direct Instantiation Not Supported. Use
Instance method to get an Instance of this class")
End If
End Sub
Public ReadOnly Property Counter() As Integer
Get
While True
If Now.Hour = 16 AndAlso Now.Minute = 0 Then
Exit While
End If
Thread.Sleep(100)
End While
SyncLock (m_objLockObject)
m_intCtr = m_intCtr + 1
End SyncLock
Return m_intCtr
End Get
End Property
End Class <Transaction(TransactionOption.Required)> Public Class Numbering2
Inherits ServicedComponent Public Shared ReadOnly Instance As Numbering2 = New
Numbering2
Private m_intCtr As Integer
Private m_objLockObject As New Object
Public Sub New()
Dim iCtr As Integer = 1 While True Dim sf As StackFrame =
New StackFrame(iCtr)
Dim l_objCallingMethod As MethodBase = sf.GetMethod() If
l_objCallingMethod Is Nothing Then
Exit While
Else
If l_objCallingMethod.Name = ".cctor" Then
If l_objCallingMethod.DeclaringType.ToString = Me.GetType.ToString
Then
Exit Sub
End If
End If
End If
iCtr = iCtr + 1
End While
Throw New NotSupportedException("Direct Instantiation Not Supported. Use
Instance method to get an Instance of this class")
End Sub
Public ReadOnly Property Counter() As Integer
Get
While True
If Now.Hour = 16 AndAlso Now.Minute = 0 Then
Exit While
End If
Thread.Sleep(100)
End While
SyncLock (m_objLockObject)
m_intCtr = m_intCtr + 1
End SyncLock
Return m_intCtr
End Get
End Property
End Class Would appreciate any comments from the group(Spark/Raj/Gaurav/Mahesh!!!)
regards, sr p.s. you can probably even try out Mahesh's article/post which talks
of getting the COM+ functionality wihout registering it on the Server!!!!
-----------------------------------------------------------
To stop getting this e-mail, or change how often it arrives, go to your E-mail
Settings.
http://groups.msn.com/BDotNet/_emailsettings.msnw
Need help? If you've forgotten your password, please go to Passport Member Services.
http://groups.msn.com/_passportredir.msnw?ppmprop=help
For other questions or feedback, go to our Contact Us page.
http://groups.msn.com/contact
If you do not want to receive future e-mail from this MSN group, or if you received
this message by mistake, please click the "Remove" link below. On the pre-addressed
e-mail message that opens, simply click "Send". Your e-mail address will be deleted
from this group's mailing list.
mailto:[EMAIL PROTECTED]