Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# covariance structure understanding?

  • Assuming

    class A { }

    class B : A { }

covariance is not supported for generic class.

Meaning - we cant do something like this :

MyConverter<B> x1= new MyConverter<B>();
MyConverter<A> x2= x1;  

Thats fine and understood.

From my reading - i understand that Covariance will be available:

"If you use a backing Generic Interface Being implemented on a Generic Class - so that access to the T type object instance will be available through those interfaces ".

I have just one problem.

Ive seen many examples of the "converter" class as a form of Stack .

But never understood " what if I want to use only 1 instance of B from a reference of A ? "

so Ive tried some code :

Create B object + values ---> use Generic Converter for B ---> use the covariance flow to get its A reference ---> now you can use it either as A or as B.

enter image description here

enter image description here

My question :

Is That the correct way of doing this ( for using covariance for 1 object only ) ?

p.s. The code is working and compiled ok. http://i.stack.imgur.com/PJ6QO.png

Ive been asking /reading a lot about this topic lately - I dive into things in order to understand them the best I can.

like image 420
Royi Namir Avatar asked Feb 10 '12 14:02

Royi Namir


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 ...

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.

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.

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

Your code compiles and works, so is it "correct"? I guess it is!

However it is not very interesting having a stack that only contains a single element; that's not really a stack. Let's think about how you might make a truly covariant and contravariant stack.

interface IPush<in T> { void Push(T item); }
interface IPop<out T> { T Pop(); }
class Stack<T> : IPush<T>, IPop<T>
{
    private class Link
    {
        public T Item { get; private set; }
        public Link Next { get; private set; }
        public Link(T item, Link next) { this.Item = item; this.Next = next; }
    }

    private Link head;
    public Stack() { this.head = null; }

    public void Push(T item)
    {
        this.head = new Link(item, this.head);
    }

    public T Pop()
    {
        if (this.head == null) throw new InvalidOperationException();
        T value = this.head.Item;
        this.head = this.head.Next;
        return value;
    }
}

And now you can use the stack covariantly for popping, and contravariantly for pushing:

Stack<Mammal> mammals = new Stack<Mammal>();
IPop<Animal> animals = mammals;
IPush<Giraffe> giraffes = mammals;
IPush<Tiger> tigers = mammals;
giraffes.Push(new Giraffe());
tigers.Push(new Tiger());
System.Console.WriteLine(animals.Pop()); // Tiger
System.Console.WriteLine(animals.Pop()); // Giraffe

What if I want to use only one instance of B from a reference of A?

Your question is "what if I want to use a Tiger but I have a reference an Animal?" The answer is "you can't" because the Animal might not be a Tiger! If you want to test whether the reference to Animal is really a tiger then say:

Tiger tiger = myAnimal as Tiger;
if (tiger != null) ...

or

if (myAnimal is Tiger) ...

What about if you want to convert class C<B> to C<A>?

That's not possible. There is no reference conversion there. The only covariant and contravariant reference conversions in C# 4 are on generic interfaces and generic delegates that are constructed with reference types as the type arguments. Generic classes and structs may not be used covariantly or contravariantly. The best thing you can do is make the class implement a variant interface.

like image 95
Eric Lippert Avatar answered Sep 27 '22 21:09

Eric Lippert


It looks like you're using the converter simply to get a reference of type A pointing to an object of type B. There's a much easier way to do that, called casting:

B b = new B();
A a = (A)b;

In fact, since A is a superclass of B, the conversion is implicit:

B b = new B();
A a = b;

Your program could be:

class Program
{
    static void Main(string[] args)
    {
        B b = new B { b1 = 22222 };
        A a = b;
        Console.WriteLine(a.a1);
        Console.WriteLine(((B)a).b1);
    }
}
like image 28
phoog Avatar answered Sep 27 '22 20:09

phoog