Tomas
Tomas

Reputation: 18117

return disposable object outside of method

How to return PdfDocument outside of the method to read properties of the object? I understand that the method will throw the object is disposed exception because using will do the disposal job before it is returned.

I am asking for refactoring ideas. Maybe Actions fits here? Please provide with code ideas.

public PdfDocument Info(string inFile, string password)
    {
        try
        {
            using (var pdf = new PdfDocument(inFile, new PdfStandardDecryptionHandler(password)))
            {
                return pdf;
            }
        }
        catch (IncorrectPasswordException)
        {
            throw new ApiException(ResponseMessageType.FilePasswordProtected);
        }
        catch (UnexpectedStructureException)
        {
            throw new ApiException(ResponseMessageType.FileDamaged);
        }
    }

Upvotes: 1

Views: 578

Answers (3)

dba
dba

Reputation: 1175

How about turning the other way, not returning the object but injecting the Action?

    public void ProcessPdf(string inFile, string password, Action<PdfDocument> action)
    {
        try
        {
          using (var pdf = new PdfDocument(inFile, new PdfStandardDecryptionHandler(password)))
           {
             action (pdf);
           }
        }
        catch (IncorrectPasswordException)
        {
            throw new ApiException(ResponseMessageType.FilePasswordProtected);
        }
        catch (UnexpectedStructureException)
        {
            throw new ApiException(ResponseMessageType.FileDamaged);
        }
    }

call it like:

ProcessPdf(iniPath, "*****", (o) => DoSomething(o))

private void DoSomething (pdfDocument doc)
{
  //....
}

pseudocode, not tested!

Upvotes: 0

Fadi Ishaq
Fadi Ishaq

Reputation: 1

First, if you want to return a disposable object, then the caller function should handle the disposing; So, no need for the using statement inside the object creation function.

When you want call the Info function to create a PdfDocument object, use try to call "Info(string,string)" and then dispose it (if it's not null) in the finally block.

        public PdfDocument Info(string inFile, string password)
        {
            try
            {
                PdfDocument pdf = new PdfDocument(inFile, new PdfStandardDecryptionHandler(password));
                return pdf;
            }
            catch (IncorrectPasswordException)
            {
                throw new ApiException(ResponseMessageType.FilePasswordProtected);
            }
            catch (UnexpectedStructureException)
            {
                throw new ApiException(ResponseMessageType.FileDamaged);
            }
        }

        /////////////

        AnotherFunction()
        {
            PdfDocument pdf = null;

            try
            {
                pdf = Info("inFile", "password");
                // Use the object
            }
            finally
            {
                pdf?.Dispose();
            }
        }

Upvotes: 0

Mathias R. Jessen
Mathias R. Jessen

Reputation: 174505

The using statement is really syntactic sugar for a try{}finally{} construct and is lowered by the compiler as follows:

// this ...
using(var thing = new DisposableThing())
{
    ...
}

// gets rewritten to:
var thing = new DisposableThing();
try
{
    ...
}
finally
{
  if(thing is IDisposable)
  {
    ((IDisposable)thing).Dispose();
  }
}

So remove the using statement from your method to prevent premature disposal:

public PdfDocument Info(string inFile, string password)
{
    try
    {
        return new PdfDocument(inFile, new PdfStandardDecryptionHandler(password));
    }
    catch (IncorrectPasswordException)
    {
        throw new ApiException(ResponseMessageType.FilePasswordProtected);
    }
    catch (UnexpectedStructureException)
    {
        throw new ApiException(ResponseMessageType.FileDamaged);
    }
}

At which point the consumer becomes responsible for disposing of it:

using (var pdf = Info(inFile, password))
{
  // read properties from `pdf` here
}

Upvotes: 5

Related Questions