Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Casting generics (covariance and contravariance?)

Tags:

c#

.net

c#-4.0

I need some advice/help on this, I can't see the wood from the trees any more.

It's a straight forward series of classes implementing some interfaces using generics.

Then I'm trying to cast the concrete types for example:

MyGenericObject<SomeObject> _obj;

IMyGenericObject<ISomeObject> _genObj = (IMyGenericObject<ISomeObject>)_obj;

// Invalid cast

I've read some articles about covariance and contravariance but not too clear why this wouldn't be possible, or how to get round it?


So, in this example:

public interface IMyObject<in T> where T : IBaseObject
{
    T Activity { get; set; }
}

wouldn't work...


....because, you can't get and set the Activity property.

In this example, I needed to do:

public interface IMyObject<out T> where T : IBaseObject
    {
        T Activity { get; }
    }

hope that helps someone, and thanks to all for help!

like image 584
sambomartin Avatar asked Dec 06 '11 14:12

sambomartin


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?

C is a general-purpose language that most programmers learn before moving on to more complex languages. From Unix and Windows to Tic Tac Toe and Photoshop, several of the most commonly used applications today have been built on C. It is easy to learn because: A simple syntax with only 32 keywords.

What is the full name of C?

In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr. Stroustroupe.

Is C programming hard?

C is more difficult to learn than JavaScript, but it's a valuable skill to have because most programming languages are actually implemented in C. This is because C is a “machine-level” language. So learning it will teach you how a computer works and will actually make learning new languages in the future easier.


2 Answers

You can only do that if you declare the interface as having a covariant (out) parameter. You can only do that if the parameter is used covariantly.

For example, if the interface IMyGenericObject<T> has a method taking a T parameter, this prevents you from declaring the parameter as covariant. Conversely, if there is a method that returns a T, that prevents you from declaring the parameter as contravariant.

EDIT

In response to your comment on SLaks's answer, I'm tempted to repeat everything Eric Lippert has ever written on co- and contravariance. See http://blogs.msdn.com/b/ericlippert/archive/tags/Covariance+and+Contravariance/ and also his answers in SO (most recently https://stackoverflow.com/a/8380213/385844)

To summarize:

You can't cast IList<string> to IList<object> because it's legal to pass a FileInfo to an IList<object>, but it is not legal to pass it to an IList<string>.

You can't cast an IList<object> to an IList<string>, because it's legal to retrieve an item from an IList<string> and assign it to a string reference, but an IList<object> might contain a FileInfo, which can't be assigned to a string reference.

EDIT 2

Since you asked for advice, it's also possible to split your interfaces into co- and contravariant parts. To continue with the list example, you could have these interfaces

public interface ICovariantList<out T>
{
    T this[int index] { get; }
    //...
}

public interface IContravariantList<in T>
{
    T this[int index] { set; }
    void Add(T item);
    //...
}

public class SomeList<T> : ICovariantList<T>, IContravariantList<T>
{
    //...
}

This allows you to use the class covariantly or contravariantly, depending on the context.

like image 174
phoog Avatar answered Oct 26 '22 13:10

phoog


You need to declare the interface as having a covariant (out) generic parameter.

like image 24
SLaks Avatar answered Oct 26 '22 14:10

SLaks