Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using try-catch in .net structure constructor

I have need of a .net structure (it mimics a connected devices internal map) and I want to use a try catch block since I'm using Marshall.PtrToStructure() and associated GChandle stuff. However I when I put the structures field assignments inside the try catch block I get this error "field1 must be fully assigned before control is returned to sender". The basic code works fine without the try catch block. Is there any way around this error while using try catch blocks? Should I use try catch?

[StructLayout( LayoutKind.Sequential )]
public struct Effects
{
    public UInt16 field_1;
    public UInt16 field_2;
    ...



    public Effects(byte[] effectsData)
    {
       GCHandle gch;
       try
       {
           gch = GCHandle.Alloc( effectsData, GCHandleType.Pinned );
           IntPtr pEffects = gch.AddrOfPinnedObject( );
           this = (Effects)Marshal.PtrToStructure( pEffects, typeof(Effects ) );
       }
       catch (Exception ex)
       {

       }
       finally
       {
           if (gch.IsAllocated)
               gch.Free( );
       }
    }
}
like image 353
Gio Avatar asked Nov 29 '22 09:11

Gio


2 Answers

The constructor must guarantee that if it returns normally then all the fields are filled in.

Suppose your code throws an exception on the first line of the try. Then you catch the exception, eat it, and return, without having ever filled in any of the fields! The compiler detects this and disallows the program.

Eating every exception is almost certainly the wrong thing to do here. Do you really want to return an uninitialized structure if there was an unhandled and unexpected arbitrary exception?

If that is what you want to do then you can simply say:

public Effects(byte[] effectsData) : this() {

that will guarantee that the fields are initialized to their default values before the ctor block runs.

But again: is that really what you want to do? This code looks incredibly dangerous to me.

like image 184
Eric Lippert Avatar answered Dec 04 '22 12:12

Eric Lippert


What do you want to happen in case of an exception? As your code stands now, if an exception occurs in the try block, the exception is swallowed (since your catch block is empty), and the structure is uninitialized -- this is exactly what the compiler is complaining about.

If you need the try-catch block only for the finally part, don't use the catch block at all but just try-finally. Let errors bubble up to the user interface by not catching them. No catch block is (almost) always better than an empty catch block. Empty catch blocks make debugging a nightmare, since your code just "doesn't work" with no indication to what went wrong.

Thus, I'd rewrite your code as follows:

public Effects(byte[] effectsData) 
{ 
     GCHandle gch = GCHandle.Alloc( effectsData, GCHandleType.Pinned ); 
     try 
     { 
         IntPtr pEffects = gch.AddrOfPinnedObject( ); 
         this = (Effects)Marshal.PtrToStructure( pEffects, typeof(Effects ) ); 
     } 
     finally 
     { 
        if (gch.IsAllocated)
            gch.Free( ); 
     } 
} 

(If an error occurs in GCHandle.Alloc, gch will not be assigned, so there's no need to include it in the try-finally block.)

like image 45
Heinzi Avatar answered Dec 04 '22 13:12

Heinzi