Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Covariance and Contravariance when implementing interfaces

I've recently decided to refresh my memory regarding C# basics, so this might be trivial, but i've bumped into the following issue:

StringCollection was used in .NET v1.0 in order to create a strongly typed collection for strings as opposed to an object based ArrayList (this was later enhanced by including Generic collections):

Taking a quick glance at StringCollection definition, you can see the following:

// Summary:
//     Represents a collection of strings.
[Serializable]
public class StringCollection : IList, ICollection, IEnumerable
{
...
    public int Add(string value);
...
}

You can see it implements IList, which contains the following declaration (among a few other declarations):

int Add(object value);

But not:

int Add(string value);

My first assumption was that it is possible due to the .NET framework covariance rules.

So just to make sure, I tried writing my own class which implements IList and changed

int Add(object value);

to retrieve a string type instead of an object type, but for my surprise, when trying to compile the project, I got an compile-time error:

does not implement interface member 'System.Collections.IList.Add(object)'

Any ideas what causes this?

Thanks!

like image 365
Mikey S. Avatar asked Aug 14 '11 01:08

Mikey S.


People also ask

What C is used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...

Is C language easy?

Compared to other languages—like Java, PHP, or C#—C is a relatively simple language to learn for anyone just starting to learn computer programming because of its limited number of keywords.

What is C in C language?

What is C? C is a general-purpose programming language created by Dennis Ritchie at the Bell Laboratories in 1972. It is a very popular language, despite being old. C is strongly associated with UNIX, as it was developed to write the UNIX operating system.

What is C full form?

History: The name C is derived from an earlier programming language called BCPL (Basic Combined Programming Language). BCPL had another language based on it called B: the first letter in BCPL.


1 Answers

The behavior is caused by the explicit implementation of IList.Add(object) rather than co/contravariance. Per the MSDN documentation, StringCollection explicitly implements IList.Add(object); the Add(string) method is unrelated. The implementation may resemble something like this:

class StringCollection : IList
{
    ...
    public int Add(string value)
    {} // implementation

    public int IList.Add (object value)
    {
        if (!value is string)) return -1;
        return Add(value as string)
    }
}

This distinction can be observed:

  StringCollection collection = new StringCollection();
  collection.Add(1); // compile error
  (collection as IList).Add(1); // compiles, runtime error
  (collection as IList).Add((object)"") // calls interface method, which adds string to collection

Addendum

The above doesn't address why this pattern is implemented. The C# language specification states that [§13.4.1, emphasis added]:

In some cases, the name of an interface member may not be appropriate for the implementing class, in which case the interface member may be implemented using explicit interface member implementation. [...]

It is not possible to access an explicit interface member implementation through its fully qualified name in a method invocation, property access, or indexer access. An explicit interface member implementation can only be accessed through an interface instance, and is in that case referenced simply by its member name.

StringCollection adheres to the required IList behavior -- IList makes no guarantee that any arbitrary object can be added to it. StringCollection makes stronger guarantees -- primarily, that it will contain only strings. The class includes its own strongly-typed methods for Add, Contains, Item, and others for the standard use case where it is accessed as a StringCollection rather than an IList. But it still functions perfectly well as an IList, accepting and returning objects, but returning an error code (as IList permits) if an attempt is made to add an item that is not a string.

Ultimately, whether an interface shows up in the class (i.e., is explicitly implemented) is at the discretion of the class author. In the case of framework classes, explicit implemenentations are included in the MSDN documentation but are not accessible as class members (e.g., shown in autocompletion contexts).

like image 174
drf Avatar answered Oct 03 '22 18:10

drf