C # – Understanding ‘in’ and ‘out’ (Generic Modifier)

in (Generic Modifier)

For generic type parameters, the in keyword specifies that the type parameter is contravariant. You can use the in keyword in generic interfaces and delegates.

Contravariance enables you to use a less derived type than that specified by the generic parameter.

An interface that has a contravariant type parameter allows its methods to accept arguments of less derived types than those specified by the interface type parameter. For example, because in .NET Framework 4, in the IComparer<T> interface, type T is contravariant, you can assign an object of the IComparer(Of Person) type to an object of the IComparer(Of Employee) type without using any special conversion methods if Employee inherits Person.

Example

The following example shows how to declare, extend, and implement a contravariant generic interface. It also shows how you can use implicit conversion for classes that implement this interface.

// Contravariant interface.
interface IContravariant<in A> { }

// Extending contravariant interface.
interface IExtContravariant<in A> : IContravariant<A> { }

// Implementing contravariant interface.
class Sample<A> : IContravariant<A> { }

class Program
{
    static void Test()
    {
        IContravariant<Object> iobj = new Sample<Object>();
        IContravariant<String> istr = new Sample<String>();

        // You can assign iobj to istr because
        // the IContravariant interface is contravariant.
        istr = iobj;
    }
}

out (generic modifier)

For generic type parameters, the out keyword specifies that the type parameter is covariant. You can use the out keyword in generic interfaces and delegates.

An interface that has a covariant type parameter enables its methods to return more derived types than those specified by the type parameter. For example, because in .NET Framework 4, in IEnumerable<T>, type T is covariant, you can assign an object of the IEnumerabe(Of String) type to an object of the IEnumerable(Of Object) type without using any special conversion methods.

A covariant delegate can be assigned another delegate of the same type, but with a more derived generic type parameter.

The classic example is IEnumerable. Since IEnumerable is covariant, you’re allowed to do the following:

IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;
Example

The following example shows how to declare, extend, and implement a covariant generic interface. It also shows how to use implicit conversion for classes that implement a covariant interface.

// Covariant interface.
interface ICovariant<out R> { }

// Extending covariant interface.
interface IExtCovariant<out R> : ICovariant<R> { }

// Implementing covariant interface.
class Sample<R> : ICovariant<R> { }

class Program
{
    static void Test()
    {
        ICovariant<Object> iobj = new Sample<Object>();
        ICovariant<String> istr = new Sample<String>();

        // You can assign istr to iobj because
        // the ICovariant interface is covariant.
        iobj = istr;
    }
}
Requirements

In a generic interface, a type parameter can be declared covariant if it satisfies the following conditions:

  • The type parameter is used only as a return type of interface methods and not used as a type of method arguments.
  • The type parameter is not used as a generic constraint for the interface methods.

For remembering easily the usage of in and out keyword (also covariance and contravariance), we can imagine inheritance as wrapping: String : Object Bar : Foo

csharpInOutGenModifiers

Share            
X
                                                                                                        

Leave a Reply

Your email address will not be published. Required fields are marked *