Consider passing base types as parameters
TypeName |
ConsiderPassingBaseTypesAsParameters |
CheckId |
CA1011 |
Category |
Microsoft.Design |
Breaking Change |
Breaking |
Cause
A method declaration includes a formal parameter that is a derived type, and the method only calls members of the parameter's base type.
Rule Description
When a base type is specified as a parameter in a method declaration, any type derived from the base type can be passed as the corresponding argument to the method. When the argument is used inside the method body, the specific method that is executed depends on the type of the argument. If the additional functionality provided by the derived type is not required, use of the base type allows the method to be more widely utilized.
How to Fix Violations
To fix a violation of this rule, change the type of the parameter to its base type.
When to Exclude Warnings
It is safe to exclude a warning from this rule if the method requires the specific functionality provided by the derived type or to enforce that only the derived type, or a more derived type, is passed to the method. In this case, the code will be more robust due to the strong type checking provided by the compiler and runtime.
Example
The following example shows a method, ManipulateFileStream
, that can only be used with a FileStream object, which violates this rule. A second method, ManipulateAnyStream
, satisfies the rule by replacing the FileStream parameter with a Stream.
Imports System
Imports System.IO
Namespace DesignLibrary
Public Class StreamUser
Sub ManipulateFileStream(ByVal stream As IO.FileStream)
If stream Is Nothing Then Throw New ArgumentNullException("stream")
Dim anInteger As Integer = stream.ReadByte()
While (anInteger <> -1)
' Do something.
anInteger = stream.ReadByte()
End While
End Sub
Sub ManipulateAnyStream(ByVal anyStream As IO.Stream)
If anyStream Is Nothing Then Throw New ArgumentNullException("anyStream")
Dim anInteger As Integer = anyStream.ReadByte()
While (anInteger <> -1)
' Do something.
anInteger = anyStream.ReadByte()
End While
End Sub
End Class
Public Class TestStreams
Shared Sub Main()
Dim someStreamUser As New StreamUser()
Dim testFileStream As New FileStream( _
"test.dat", FileMode.OpenOrCreate)
Dim testMemoryStream As New MemoryStream(New Byte() {})
' Cannot be used with testMemoryStream.
someStreamUser.ManipulateFileStream(testFileStream)
someStreamUser.ManipulateAnyStream(testFileStream)
someStreamUser.ManipulateAnyStream(testMemoryStream)
testFileStream.Close()
End Sub
End Class
End Namespace
using System;
using System.IO;
namespace DesignLibrary
{
public class StreamUser
{
int anInteger;
public void ManipulateFileStream(FileStream stream)
{
while((anInteger = stream.ReadByte()) != -1)
{
// Do something.
}
}
public void ManipulateAnyStream(Stream anyStream)
{
while((anInteger = anyStream.ReadByte()) != -1)
{
// Do something.
}
}
}
class TestStreams
{
static void Main()
{
StreamUser someStreamUser = new StreamUser();
MemoryStream testMemoryStream = new MemoryStream(new byte[] {});
using(FileStream testFileStream =
new FileStream("test.dat", FileMode.OpenOrCreate))
{
// Cannot be used with testMemoryStream.
someStreamUser.ManipulateFileStream(testFileStream);
someStreamUser.ManipulateAnyStream(testFileStream);
someStreamUser.ManipulateAnyStream(testMemoryStream);
}
}
}
}
using namespace System;
using namespace System::IO;
namespace DesignLibrary
{
public ref class StreamUser
{
int anInteger;
public:
void ManipulateFileStream(FileStream^ stream)
{
while((anInteger = stream->ReadByte()) != -1)
{
// Do something.
}
}
void ManipulateAnyStream(Stream^ anyStream)
{
while((anInteger = anyStream->ReadByte()) != -1)
{
// Do something.
}
}
};
}
using namespace DesignLibrary;
static void main()
{
StreamUser^ someStreamUser = gcnew StreamUser();
FileStream^ testFileStream =
gcnew FileStream("test.dat", FileMode::OpenOrCreate);
MemoryStream^ testMemoryStream =
gcnew MemoryStream(gcnew array<Byte>{});
// Cannot be used with testMemoryStream.
someStreamUser->ManipulateFileStream(testFileStream);
someStreamUser->ManipulateAnyStream(testFileStream);
someStreamUser->ManipulateAnyStream(testMemoryStream);
testFileStream->Close();
}
While this rule currently fires on virtual methods in Visual Studio 2005, in future versions of Visual Studio this will be changed so that following will no longer cause ConsiderPassingBaseTypesAsParameters to fire.