I have small doubt in CoVariance and ContraVariance.. See the Following Code..
interface IGetElement<out T>
{
int Counter { get; }
T GetNext();
}
interface IAddElement<in T>
{
void Add(T t);
}
class Collection<T> : IAddElement<T>, IGetElement<T> where T : Fruit
{
List<T> tList = new List<T>();
private int _counter = 0;
public int Count { get { return tList.Count; } }
public void Add(T t)
{
tList.Add(t);
}
int IGetElement<T>.Counter
{
get { return _counter; }
}
public T GetNext()
{
return tList[_counter++];
}
public void Rset()
{
_counter = 0;
}
}
abstract class Fruit
{
public abstract void Taste();
}
class Apple : Fruit
{
public override void Taste()
{
Console.WriteLine("Like Apple");
}
}
This is the sample code.. And now the Client is
static void Main(string[] args)
{
IGetElement<Fruit> covarience = new Collection<Apple>(); // CoVarience..
IAddElement<Apple> contravarience = new Collection<Fruit>();//ContraVarience.. Compiling fine and working also fine... :)
IGetElement<Fruit> fruits = new Collection<Apple>();
IAddElement<Fruit> apples2 = fruits as IAddElement<Apple>;//Here its Compiler error : Cannot implicitly convert type 'Test.IAddElement<Test.Apple>' to 'Test.IAddElement<Test.Fruit>'. An explicit conversion exists (are you missing a cast?)
IAddElement<Apple> apples1 = fruits as IAddElement<Fruit>;//This is not posible
/* Why this is not possible..? In this case No Compiler Error But Run Time error ie.,
apples1 is NULL.. I don't know why.. because.. in fruits cantains apple only but
It is unable it caste it as ContrVariantly.. ?------------1 */
IAddElement<Apple> apples = fruits as IAddElement<Apple>;//This is posible
IGetElement<Fruit> f = apples as IGetElement<Apple>;//This is posible..
/* Why this is posible.. ? here we are casting t as CoVariantly..
If ------------1 is not posible how this would be posible... yes.. I am casting to
actual object which is not Null.. ? -----------2 */
}
Please answer my Question in Commented Source code... :) --------1,---------2.
Thanks And Regards, Dinesh
To expand a bit on James' answer:
- Why this is not possible? In this case there is no compiler error but at runtime apples1 is null. I don't know why.
Local variable fruits at runtime refers to an object of type Collection<Apple>
. That is, a collection which contains only apples.
You are asking "can I add any fruit to this collection?" No. You can only add apples, not any fruit. Therefore the result is null.
The reason this fails at runtime and not at compile time is because the compile-time type of fruits is an interface type, and you are converting it to a different interface type. Any two interfaces might be implemented by a given object; the compiler does not do flow analysis to determine that fruits is only ever assigned one particular type. Therefore the check cannot be done until runtime.
- Why this is posible? Here we are converting covariantly.
There are two conversions here. First apples is converted to IGetElement<Apple>
and then that is covariantly converted to IGetElement<Fruit>
.
The first conversion succeeds because local variable apples refers to a Collection<Apple>
which implements IGetElement<Apple>
. You are asking "is this object something that can hand me an apple?" and the answer is "yes".
The second conversion succeeds because the compiler knows that "an object that can hand me an apple" can be safely treated as "an object that can hand me a fruit".
Is that now clear?