Method Parameter Types in C#

This article has been excerpted from book "The Complete Visual C# Programmer's Guide" from the Authors of C# Corner.

C# supports three parameter-passing styles to class member methods: [in], ref, and out. All data types in C# are passed by reference, but their default behavior is handled differently depending upon whether they are a value or reference type. The [in] parameter style is the default for value types, so you do not have to explicitly define it in your method. In fact, defining it explicitly causes a compile error. The [in] parameter style indicates that the value type parameter being passed is not being altered upon returning from the method. Thus, the value of passed parameters of a value type, by default, cannot be changed.

For integral types and immutable classes such as strings, the C# [in] parameter type is similar to the C++ const type&. The [in] type has no effect on mutable classes classes whose contents can be changed. The default behavior of references to mutable objects is handled as if the object was preceded with the ref keyword. In other words, with the [in] keyword, you can pass the value's address to the method, but the value itself cannot be changed. To make the value changeable, use the C# parameter type ref.

The C# ref parameter type works like the type& standard reference in C++. A reference parameter does not create a new storage location. Instead, it represents the same storage location as the variable given as the argument in the function member invocation. Thus, the value of a reference parameter is always the same as the underlying variable.

A variable must be assigned before it can be passed as a reference parameter in a function member invocation. Within a function member, a reference parameter is considered initially assigned. Within an instance method or instance accessor of a struct type, the this keyword behaves exactly as a reference parameter of the struct type.

The out parameter is for explicitly referencing a parameter that will be filled by the called method. It has no complement in C++, but in COM+ the distinction was made in order to fulfill thorough marshalling back from a method. An out parameter differs from the ref parameter in that the caller doesn't need to initialize the variable prior to calling the method. Instead, a reference to the object can be sent uninitialized and initialized by the called method and then returned after instantiation. As with the ref parameter, an output parameter does not create a new storage location. Instead, it represents the same storage location as the variable given as the argument in the function member invocation. Thus, the value of an output parameter is always contained in the underlying variable that was passed into the method. Note that although an output parameter need not be assigned a value when it is passed into a method, it must be assigned a value when it returns from a method, otherwise the compiler will give an error.

Because structs are value types, when an instance of one is passed to a method, a copy is created of the structure. You can use the out keyword with a struct parameter to prevent the creation of large temporary storage space of a structure on the stack. C# syntax encourages the return only of values or objects you really need and discourages the storage of temporary objects. This seems a sensible alternative to the C++ approach. In addition, the parameter distinction simplifies component programming for the developer.

Listing 5.68 provides an example of how to use the [in], ref, and out parameter modifiers.

Listing 5.68: Parameter Modifiers Example 1


// example method parameter usage; in out ref

using
System;

public
class ThirdFourthPower
{
    public void XPower(Int32 intparam1, ref Int32 intparam2, out Int32 intparam3,
    out Int32 intparam4)
    {
        intparam3 = intparam1 * intparam1 * intparam1;
        intparam2 = intparam1 * intparam1 * intparam1 * intparam1;
        // ERROR: you cannot use out parameters as a value, right value here
        // intparam2 = intparam3 * intparam1;
        intparam4 = intparam1 + intparam2 / intparam1; // notice operator
        // precedence
    }
}


class
MathyApp
{
    public static void Main()
    {
        ThirdFourthPower app1 = new ThirdFourthPower();
        Int32 nTriple1; // out parameters need not be initialized because filled in callee
        Int32 nTriplePlus2; // out
        Int32 nQuadruple = 0; // ref parameters must be initialized or assigned
        // otherwise you receive ERROR : Use of unassigned local variable nQuadruple
        app1.XPower(3, ref nQuadruple, out nTriple1, out nTriplePlus2);
        Console.WriteLine("out1: {0}", nTriple1.ToString()); // out parameter,
        // 27
        Console.WriteLine("ref: {0}", nQuadruple.ToString()); // ref parameter,
        // 81
        Console.WriteLine("out2: {0}", nTriplePlus2.ToString()); // out parameter
        // 27
        // you should not use ref for returning values; use it if you really
        // need in-place change
        // note that in parameters are also references, but const, so you
        // cannot change them.
        Console.ReadLine();
    }
}


The screen output of this code is given in Figure 5.25.

Figure5.25.gif

Figure 5.25: Screen Output Generated from Listing 5.68

Listing 5.69 presents a complete array example with out and ref parameters.

Listing 5.69: Parameter Modifiers Example 2


// in & out & ref - passing arrays

using
System;

class
MyApp
{
    // out
    static public void FillArray(out int[] myArray)
    {
        // Initialize the array:
        myArray = new int[5] { 1, 2, 3, 4, 5 };
    }

    // ref
    public static void FillArray2(ref int[] arr)
    {
        // Create the array on demand:
        if (arr == null)
            arr = new int[10];
        // Otherwise fill the array:
 
       arr[0] = 19;
        arr[4] = 1919;
    }
 
   // implicit ref default for references, not in
    static public void WriteArray(int[] myArray)
    {
        // myArray[2] = 19; // CAVEAT: this is also valid
        Console.WriteLine("Array elements are:");
        for (int i = 0; i < myArray.Length; i++)
            Console.WriteLine(myArray[i]);
    }

    public static void Main()
    {
        int[] myArray; // Initialization is not required
        FillArray(out myArray);
        WriteArray(myArray);
        // Initialize the array:
        int[] myArray2 = { 1, 2, 3, 4, 5 };
        FillArray2(ref myArray2);
        WriteArray(myArray2);
        Console.ReadLine();
    }
 }


Figure 5.26 shows the output listing the array elements.

Figure5.26.gif

Figure 5.26: Screen Output Generated from Listing 5.69

Table 5.9 compares method parameter modifiers for none, [in], and ref derived from the tests.

table5.9.gif

Table 5.9: Method Parameter Modifiers

Listing 5.70 contains a third example of the use of parameter modifiers.

Listing 5.70: Parameter Modifiers Example 3


using
System;

public
class SomeItems
{
    public int One;
    public string Two;
}


public
class App
{
    public int m_three = 5;
    public int methodTwo(SomeItems o, string s)
    {
        o.One = m_three;
        s = "BlaBla";
        return 0;
    }

    public int methodTwo2(SomeItems o)
    {
        o.One = m_three;
        o.Two = "Is Gone";
        return 0;
    }

    public static void Main(string[] args)
    {
        App _a = new App();
        SomeItems si = new SomeItems();
        si.One = 1;
        si.Two = "Goodbye string";
        Console.WriteLine("Before = {0} - {1}", si.One, si.Two);
        _a.methodTwo(si, si.Two);
        Console.WriteLine("After = {0} - {1}", si.One, si.Two);
        _a.methodTwo2(si);
        Console.WriteLine("After = {0} - {1}", si.One, si.Two);
        Console.ReadLine();
        return;
    }
}


Figure 5.27 contains output from this code listing.

Figure5.27.gif

Figure 5.27: Screen Output Generated from Listing 5.70

Please refer to C# Language Specification (http://msdn.microsoft.com/en-us/library/aa645597(VS.71).aspx) for more details and recent updates to the C# language.

The params keyword allows you specify a method parameter that takes an argument where the number of arguments is variable.

Only one params keyword is permitted in a method declaration, and no additional parameters can follow the params keyword.

Listing 5.71:Params Example


//params keyword

using
System;

public
class MyClass
{
    public static void UseParams(params int[] list)
    {
        for (int i = 0; i < list.Length; i++)
            Console.WriteLine(list[i]);
        Console.WriteLine();
    }

    public static void UseParams2(params object[] list)
    {
        for (int i = 0; i < list.Length; i++)
            Console.WriteLine((object)list[i]);
        Console.WriteLine();
    }

    public static void Main()
    {
        UseParams(1, 2, 3);
        UseParams2(1, 'a', "test");
        int[] myarray = new int[3] { 10, 11, 12 };
        UseParams(myarray);
        Console.ReadLine();
    }
}


Figure 5.28 contains the output generated by this listing.

Figure5.28.gif

Figure 5.28: Screen Output Generated from Listing 5.71

Conclusion


Hope this article would have helped you in understanding Method Parameter Types in C#. See other articles on the website on .NET and C#.

visual C-sharp.jpg
The Complete Visual C# Programmer's Guide covers most of the major components that make up C# and the .net environment. The book is geared toward the intermediate programmer, but contains enough material to satisfy the advanced developer.


Similar Articles
C# Corner
C# Corner started as an online community for software developers in 1999.