|
I have an object that creates an expensive COM object as soon as my object's Constructor is called. This COM object is treated as a private field in my object.
My object is then responsible releasing that COM object. Not releasing it is expensive and problematic.
So I put the release code for the COM object in my object's destructor, assuming my object's destructor would be called as soon as my object was set to NULL or went out of scope. However, this is not the case. My object's destructor is not called until the garbage collector runs.
This is a problem. I need my object to release the COM object as soon as it's not needed anymore. If I don't, there are problems with the COM server application - ie, it won't close, etc.
How can I insure that my object releases the COM object as soon as my object is set to null, or goes out of scope? Where do I put the COM release code?
|
|
|
|
|
You can't. You can use the dispose/finalise mechanism to let your users call Dispose to close it, or for finalise to do it when the object is GC, if dispose was not called. Welcome to garbage collection.
Christian Graus
No longer a Microsoft MVP, but still happy to answer your questions.
|
|
|
|
|
Well, that's painful. Thanks for the quick answer, though.
|
|
|
|
|
This suggests, then, that I shouldn't even bother putting the COM release code in my destructor, right? The COM object will be released anyway when my object gets GC'ed, correct?
|
|
|
|
|
Any object that uses any unmanaged resources should implement the IDisposable interface, so that the resources can be released in a controlled manner.
You have no control over when the object is garbage collected, and there is actually no guarantee that the object is ever garbage collected.
Despite everything, the person most likely to be fooling you next is yourself.
|
|
|
|
|
"Yes, but then I wouldn't be watching TV. You can see my dilemma, right?"
Sigh.
|
|
|
|
|
I have this problem with Enterprise Architect (modelling software from Sparx). The program exposes a COM automation interface for add ins, and when you write an add in with C# it can happen that the application refuses to close because your add in's COM reference which has not been garbage collected.
Sparx recommends to call GC.Collect() and GC.WaitForPendingFinalizers(). Maybe you can do this in your Dispose() method after releasing the COM reference. It's often said one should not call the GC methods for performance reasons, but when it's about releasing a big COM object they're probably justified.
|
|
|
|
|
Wrong. Non-managed resources, need to be dealt with in your code. The idea is you impliment IDisposable, so the user can call Dispose to force cleanup, but write code that does the cleanup if Dispose has not been called.
Christian Graus
No longer a Microsoft MVP, but still happy to answer your questions.
|
|
|
|
|
As Guffa pointed out, the GC has no knowledge of how to release unmanaged memory, which includes COM objects. It expects that your managed class will provide the necessary logic to free those resources during GC by implementing IDisposable .
Scott Dorman Microsoft® MVP - Visual C# | MCPD
President - Tampa Bay IASA
[ Blog][ Articles][ Forum Guidelines] Hey, hey, hey. Don't be mean. We don't have to be mean because, remember, no matter where you go, there you are. - Buckaroo Banzai
|
|
|
|
|
After nulling all references to the COM object, you can call GC.Collect () to force garbage collection. See ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.NETDEVFX.v20.en/cpref2/html/O_T_System_GC_Collect.htm
|
|
|
|
|
yes, that's how I release the COM object in my destructor. But that's not the question here. The point is, unless my client (who created my object) calls Garbage Collection explicitly, my destructor won't be called in a timely fashion.
|
|
|
|
|
Maybe you could figure out when the client is done with the object. Is there a method in the object that is called as a final operation? If so, you could invoke garbage collection at that point.
Or (depending on the particular usage pattern) you might be able to detect when the client is X seconds away from not needing the object, and set a timer to force garbage collection after X+1 seconds.
|
|
|
|
|
JoeRip wrote: The point is, unless my client (who created my object) calls Garbage Collection explicitly, my destructor won't be called in a timely fashion.
That's one of the drawbacks to a garbage collected runtime. The idea is that you implement the IDispsoable interface (actually, the Dispose pattern[^]) which tells the GC how to release your unmanaged memory and signals to the caller (client) that they should call Dispose() when they are done using your object. If you need a stronger assurance that your resources get cleaned up then you can implement a finalizer (see the above reference article for issues/concerns about implementing finalizers) and if you absolutely need to guarantee the finalizer gets called you need use a "critical finalizable object" and inherit from CriticalFinalizerObject .
Scott Dorman Microsoft® MVP - Visual C# | MCPD
President - Tampa Bay IASA
[ Blog][ Articles][ Forum Guidelines] Hey, hey, hey. Don't be mean. We don't have to be mean because, remember, no matter where you go, there you are. - Buckaroo Banzai
|
|
|
|
|
Calling GC.Collect() directly is generally a bad idea.
Scott Dorman Microsoft® MVP - Visual C# | MCPD
President - Tampa Bay IASA
[ Blog][ Articles][ Forum Guidelines] Hey, hey, hey. Don't be mean. We don't have to be mean because, remember, no matter where you go, there you are. - Buckaroo Banzai
|
|
|
|
|
Hi all...
I have developed a sharepoint dll in c#...
I am calling the dll through my exe....i.e it is a win32 application visual studio 2005.....How can i debug the c# dll....
thank you
manju
Hi..
I am Mnaju.I have Completed my B.E Computers Science.Lokking for a job.I am interested in VC++
manju
|
|
|
|
|
Open the project, attach the debugger to the process that consumes your dll and set breakpoints.
Christian Graus
No longer a Microsoft MVP, but still happy to answer your questions.
|
|
|
|
|
I want to get,
how many rows and columns are hidden in an excel sheet
Is there any direct function as i have to check each row and column, and check whether it is hidden or not.
|
|
|
|
|
I am new to C#, and have come across a situation where I need to perform different tasks based on the criteria value (string).
Thought of using 'switch' statement, I know (from C++), if you order the 'case' statements according to most frequenly occuring 'cases' at the top, it will optimise the 'switch' statement (don't know for sure, but I practiced it), but in C#, order of the 'cases' doesn’t matter.
In my situation, I would end up with around 50 'cases', so I would like to know if there are any other alternatives (to improve efficiency) apart from 'switch' statement?
Any thought/help would be greatly appreciated.
|
|
|
|
|
scody wrote: but in C#, order of the 'cases' doesn’t matter.
What on earth makes you think that ?
Yes, put your most common cases near the top, as they will get checked first, the MSIL for a switch is no different to a bunch of if/then/else statements. switch is just more human readable.
Christian Graus
No longer a Microsoft MVP, but still happy to answer your questions.
|
|
|
|
|
Christian Graus wrote: What on earth makes you think that ?
One of the books on C# stated
"One intriguing point about the switch statement in C# is that the order of the cases doesn’t matter—we can even put the default case first!"
This statement made me think..
|
|
|
|
|
scody wrote: One of the books on C# stated
"One intriguing point about the switch statement in C# is that the order of the cases doesn’t matter—we can even put the default case first!"
This statement made me think..
That statement is talking about the syntax of the switch construct, not the performance.
The performance is a whole different matter:
The order of the case labels matters if you only have five of less of them. Then you should place the most commonly used ones first.
If you have more than five case labels the switch uses a hash table, so then the order of the case labels doesn't matter at all.
(I determined this by performance testing a switch in C# 3 (VS2008) targetting framework 3.5. The implementation may of course differ in older versions of the compiler or framework, but I doubt that this was ever any different.)
Despite everything, the person most likely to be fooling you next is yourself.
|
|
|
|
|
Guffa wrote: The order of the case labels matters if you only have five of less of them. Then you should place the most commonly used ones first.
If you have more than five case labels the switch uses a hash table, so then the order of the case labels doesn't matter at all.
References?
|
|
|
|
|
Guffa wrote: If you have more than five case labels the switch uses a hash table, so then the order of the case labels doesn't matter at all.
Wow - I did not know that. I doubt very much that has always been the case, the C# 1.0 book I read delved into MSIL a lot and never mentioned it. I worked out this week that the TryParse methods arrived in 2.0, I suspect that sort of stuff did not come before 2.0 at least.
Christian Graus
No longer a Microsoft MVP, but still happy to answer your questions.
|
|
|
|
|
Christian Graus wrote: Wow - I did not know that.
Yeah I just tested it. The claim is BS. It creates the same construct regardless of the number of cases. It will reorganize cases to make the lookup more efficient, but there is NO hashtable!
|
|
|
|
|
leppie wrote: It creates the same construct regardless of the number of cases.
Not at all.
Here is the generated code for a switch containing five case labels and one containing six case labels. Do you see the fundamental difference?
00000084 mov esi,dword ptr [ebp-44h]
00000087 test esi,esi
00000089 je 000000ED
0000008b mov edx,dword ptr ds:[02C33098h]
00000091 mov ecx,esi
00000093 call 7795C574
00000098 mov edi,eax
0000009a test edi,edi
0000009c jne 000000ED
0000009e mov edx,dword ptr ds:[02C3309Ch]
000000a4 mov ecx,esi
000000a6 call 7795C574
000000ab mov edi,eax
000000ad test edi,edi
000000af jne 000000ED
000000b1 mov edx,dword ptr ds:[02C330A0h]
000000b7 mov ecx,esi
000000b9 call 7795C574
000000be mov edi,eax
000000c0 test edi,edi
000000c2 jne 000000ED
000000c4 mov edx,dword ptr ds:[02C330A4h]
000000ca mov ecx,esi
000000cc call 7795C574
000000d1 mov edi,eax
000000d3 test edi,edi
000000d5 jne 000000ED
000000d7 mov edx,dword ptr ds:[02C330A8h]
000000dd mov ecx,esi
000000df call 7795C574
000000e4 mov edi,eax
000000e6 test edi,edi
000000e8 jne 000000ED
000000ea nop
000000eb jmp 000000ED
0000008a mov ebx,dword ptr [ebp-44h]
0000008d test ebx,ebx
0000008f je 00000148
00000095 cmp dword ptr ds:[02B284BCh],0
0000009c jne 0000011F
000000a2 mov ecx,7913386Ch
000000a7 call FCAC0A5C
000000ac mov esi,eax
000000ae mov ecx,esi
000000b0 mov edx,6
000000b5 call 75929474
000000ba push 0
000000bc mov edx,dword ptr ds:[02B23098h]
000000c2 mov ecx,esi
000000c4 call 75954260
000000c9 push 1
000000cb mov edx,dword ptr ds:[02B2309Ch]
000000d1 mov ecx,esi
000000d3 call 75954260
000000d8 push 2
000000da mov edx,dword ptr ds:[02B230A0h]
000000e0 mov ecx,esi
000000e2 call 75954260
000000e7 push 3
000000e9 mov edx,dword ptr ds:[02B230A4h]
000000ef mov ecx,esi
000000f1 call 75954260
000000f6 push 4
000000f8 mov edx,dword ptr ds:[02B230A8h]
000000fe mov ecx,esi
00000100 call 75954260
00000105 push 5
00000107 mov edx,dword ptr ds:[02B230ACh]
0000010d mov ecx,esi
0000010f call 75954260
00000114 lea edx,ds:[02B284BCh]
0000011a call 76234066
0000011f lea eax,[ebp-54h]
00000122 push eax
00000123 mov ecx,dword ptr ds:[02B284BCh]
00000129 mov edx,ebx
0000012b call 75789F50
00000130 mov esi,eax
00000132 test esi,esi
00000134 je 00000148
00000136 mov eax,dword ptr [ebp-54h]
00000139 cmp eax,6
0000013c jae 00000145
0000013e jmp dword ptr [eax*4+03C41798h]
00000145 nop
00000146 jmp 00000148
Despite everything, the person most likely to be fooling you next is yourself.
|
|
|
|
|