Do not ignore method results

TypeName

DoNotIgnoreMethodResults

CheckId

CA1806

Category

Microsoft.Usage

Breaking Change

Non Breaking

Cause

A new object is created but never used.

- or -

A method that creates and returns a new string is called and the new string is never used.

- or -

A COM or P/Invoke method that returns an HRESULT or error code that is never used.

Rule Description

This rule helps make you aware of circumstances such as the following when they appear in your code:

  • Unnecessary object creation and the associated garbage collection of the unused object degrade performance.

  • Strings are immutable. Methods such as ToUpper return a new instance of a string instead of modifying the instance of the string in the calling method.

  • Ignoring an HRESULT or error code can lead to unexpected behavior in error conditions or to low-resource conditions.

How to Fix Violations

If method A creates a new instance of B object that is never used, pass the instance as an argument to another method or assign the instance to a variable. If the object creation is unnecessary, remove it.

- or -

Method A calls method B but does not use the new string instance that method B returns. Pass the instance as an argument to another method, assign the instance to a variable, or remove the call if it is unnecessary.

- or -

Method A calls method B but does not use the HRESULT or error code that the method returns. Use the result in a conditional statement, assign the result to a variable, or pass it as an argument to another method.

When to Suppress Warnings

Do not suppress a warning from this rule unless the act of creating the object serves some purpose.

Example

The following example shows a class that ignores the result of calling Trim.

Imports System

Namespace Samples

    Public Class Book

        Private ReadOnly _Title As String 

        Public Sub New(ByVal title As String)

            If title IsNot Nothing Then 
                ' Violates this rule                
                title.Trim()
            End If

            _Title = title

        End Sub 

        Public ReadOnly Property Title() As String 
            Get 
                Return _Title
            End Get 
        End Property 

    End Class 

End Namespace
using System;

namespace Samples
{
    public class Book
    {
        private readonly string _Title;

        public Book(string title)
        {
            if (title != null)
            {
                // Violates this rule                
                title.Trim();
            }

            _Title = title;
        }

        public string Title
        {
            get { return _Title; }
        }
    }
}
using namespace System;

namespace Samples
{
    public ref class Book   
    { 
        private:        
            initonly String^ _Title;

        public:
        Book(String^ title)        
        {               
            if (title != nullptr)            
            {                  
                // Violates this rule                
                title->Trim();            
            }
                _Title = title;        
            }

        property String^ Title        
        {            
            String^ get() { return _Title; }        
        }    
    };
}

The following example fixes the previous violation by assigning the result of Trim back to the variable it was called on.

Imports System

Namespace Samples

    Public Class Book

        Private ReadOnly _Title As String 

        Public Sub New(ByVal title As String)

            If title IsNot Nothing Then
                title = title.Trim()
            End If

            _Title = title

        End Sub 

        Public ReadOnly Property Title() As String 
            Get 
                Return _Title
            End Get 
        End Property 

    End Class 

End Namespace
using System;

namespace Samples
{
    public class Book
    {
        private readonly string _Title;

        public Book(string title)
        {
            if (title != null)
            {
                title = title.Trim();
            }

            _Title = title;
        }

        public string Title
        {
            get { return _Title; }
        }
    }
}
using namespace System;

namespace Samples
{    
    public ref class Book    
    {    
    private:        
        initonly String^ _Title;

    public:
        Book(String^ title)        
        {               
            if (title != nullptr)            
            {                        
                title = title->Trim();            
            }

            _Title = title;        
        }

        property String^ Title        
        {            
            String^ get() { return _Title; }        
        }    
    };
}

The following example shows a method that does not use an object that it creates.

Note

This violation cannot be reproduced in Visual Basic.

using System;

namespace Samples
{
    public class Book
    {
        public Book()
        {
        }

        public static Book CreateBook()
        {
            // Violates this rule             
            new Book();
            return new Book();
        }
    }
}
using namespace System;

namespace Samples
{    
    public ref class Book    
    {
    public:
        Book()        
        {        
        }

        static Book^ CreateBook()        
        {
            // Violates this rule             
            gcnew Book();            
            return gcnew Book();        
        }    
    };
}

The following example fixes the previous violation by removing the unnecessary creation of an object.

using System;

namespace Samples
{
    public class Book
    {
        public Book()
        {
        }

        public static Book CreateBook()
        {
            return new Book();
        }
    }
}
using namespace System;

namespace Samples
{
    public ref class Book    
    {
    public:
        Book()        
        {           
        }
        static Book^ CreateBook()        
        {            
            return gcnew Book();        
        }            
    };
}

The following example shows a method that ignores the error code that the native method GetShortPathName returns.

Imports System
Imports System.ComponentModel
Imports System.IO
Imports System.Runtime.InteropServices
Imports System.Text

Namespace Samples

    Public Module FileIO

        Public Function GetShortPath(ByVal longPath As String) As String

            longPath = Path.GetFullPath(longPath)

            Const MAX_PATH As Integer = 260

            Dim shortPathBuffer As New StringBuilder(MAX_PATH)

            ' Violates this rule
            NativeMethods.GetShortPathName(longPath, shortPathBuffer, shortPathBuffer.Capacity)

            Return shortPathBuffer.ToString()

        End Function 

    End Module 

    Friend Module NativeMethods

        <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True, BestFitMapping:=False, ThrowOnUnmappableChar:=True)> _
        Public Function GetShortPathName(ByVal lpszLongPath As String, ByVal lpszShortPath As StringBuilder, ByVal cchBuffer As UInteger) As UInteger 
        End Function 

    End Module 

End Namespace
using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;

namespace Samples
{
    public static class FileIO
    {
        public static string GetShortPath(string longPath)
        {
            longPath = Path.GetFullPath(longPath);

            const int MAX_PATH = 260;

            StringBuilder shortPathBuffer = new StringBuilder(MAX_PATH);

            // Violates this rule
            NativeMethods.GetShortPathName(longPath, shortPathBuffer, (uint)shortPathBuffer.Capacity);

            return shortPathBuffer.ToString();
        }
    }

    internal static class NativeMethods
    {
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
        public static extern uint GetShortPathName(string lpszLongPath, StringBuilder lpszShortPath, uint cchBuffer);
    }
}
#include "stdafx.h" 

using namespace System;
using namespace System::ComponentModel;
using namespace System::IO;
using namespace System::Runtime::InteropServices;
using namespace System::Text;

namespace Samples
{
    private ref class NativeMethods sealed
    {
    private:
        NativeMethods()
        {
        }

    internal:

        [DllImport("kernel32.dll", CharSet=CharSet::Auto, SetLastError=true, BestFitMapping=false, ThrowOnUnmappableChar=true)]
        static unsigned int GetShortPathName(String^ lpszLongPath, StringBuilder^ lpszShortPath, unsigned int cchBuffer);
    };
    
    public ref class FileIO sealed
    {
    private:
        FileIO()
        {
        }

    public:
        static String^ GetShortPath(String^ longPath)
        {
            longPath = Path::GetFullPath(longPath);

            const int MAX_PATH = 260;

            StringBuilder^ shortPathBuffer = gcnew StringBuilder(MAX_PATH);

            // Violates this rule
            NativeMethods::GetShortPathName(longPath, shortPathBuffer, shortPathBuffer->Capacity);

            return shortPathBuffer->ToString();
        }
    };
}

The following example fixes the previous violation by checking the error code and throwing an exception when the call fails.

Namespace Samples

    Public Module FileIO_1

        Public Function GetShortPath(ByVal longPath As String) As String

            longPath = Path.GetFullPath(longPath)

            Const MAX_PATH As Integer = 260

            Dim shortPathBuffer As New StringBuilder(MAX_PATH)

            ' GetShortPathName returns 0 when the operation fails 
            If NativeMethods.GetShortPathName(longPath, shortPathBuffer, shortPathBuffer.Capacity) = 0 Then 

                ' Note: The constructor of Win32Exception will automatically 
                ' set Win32Exception.NativeErrorCode to Marshal.GetLastWin32Error() 
                Throw New Win32Exception()

            End If 

            Return shortPathBuffer.ToString()

        End Function 

    End Module 

    Friend Module NativeMethods_1

        <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True, BestFitMapping:=False, ThrowOnUnmappableChar:=True)> _
        Public Function GetShortPathName(ByVal lpszLongPath As String, ByVal lpszShortPath As StringBuilder, ByVal cchBuffer As UInteger) As UInteger 
        End Function 

    End Module 

End Namespace
namespace Samples
{
    public static class FileIO_1
    {
        public static string GetShortPath(string longPath)
        {
            const int MAX_PATH = 260;

            StringBuilder shortPathBuffer = new StringBuilder(MAX_PATH);

            // GetShortPathName returns 0 when the operation fails 
            if (NativeMethods.GetShortPathName(longPath, shortPathBuffer, (uint)shortPathBuffer.Capacity) == 0)
            {
                // Note: The constructor of Win32Exception will automatically 
                // set Win32Exception.NativeErrorCode to Marshal.GetLastWin32Error() 
                throw new Win32Exception();
            }

            return shortPathBuffer.ToString();
        }
    }

    internal static class NativeMethods_1
    {
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
        public static extern uint GetShortPathName(string lpszLongPath, StringBuilder lpszShortPath, uint cchBuffer);
    }
}
#include "stdafx.h" 

using namespace System;
using namespace System::ComponentModel;
using namespace System::IO;
using namespace System::Runtime::InteropServices;
using namespace System::Text;

namespace Samples
{
    private ref class NativeMethods_1 sealed
    {
    private:
        void NativeMethods()
        {
        }

    internal:

        [DllImport("kernel32.dll", CharSet=CharSet::Auto, SetLastError=true, BestFitMapping=false, ThrowOnUnmappableChar=true)]
        static unsigned int GetShortPathName(String^ lpszLongPath, StringBuilder^ lpszShortPath, unsigned int cchBuffer);
    };
    
    public ref class FileIO_1 sealed
    {
    private:
        void FileIO()
        {
        }

    public:
        static String^ GetShortPath(String^ longPath)
        {
            longPath = Path::GetFullPath(longPath);

            const int MAX_PATH = 260;

            StringBuilder^ shortPathBuffer = gcnew StringBuilder(MAX_PATH);

             // GetShortPathName returns 0 when the operation fails 
            if (NativeMethods::GetShortPathName(longPath, shortPathBuffer, shortPathBuffer->Capacity) == 0)
            {
                // Note: The constructor of Win32Exception will automatically 
                // set Win32Exception.NativeErrorCode to Marshal.GetLastWin32Error() 
                throw gcnew Win32Exception();
            }


            return shortPathBuffer->ToString();
        }
    };
}