Using generics is declared as a button, but is considered as a control internal to the class. What for?

What a wonderful site I have been hiding here, reading other questions for ages, but now I have one of mine.

My workmate wrote a class very similar to the one below. As soon as I saw this, I knew that this would not work, but I have no explanation why it does not work.

What he expected when declaring it as ControlItem<Button>is that the Draw (Button) method will be called when using the base to call Draw (). Instead, we always throw an exception.

Is this a problem of covariance?

public abstract class ControlItem
{
    public ControlItem()
    {
    }

    abstract public void Draw();
}

public class ControlItem<T> : ControlItem where T : Control, new()
{
    public T MyControl { get; set; }

    private ControlItem()
    {       }

    public ControlItem(T control)
        : base()
    {
        MyControl = control;
    }

    public override void Draw()
    {
        Draw(this.MyControl);
    }

    public void Draw(Control cntrl)
    {
        throw new NotImplementedException();
    }

    public void Draw(Button button)
    {
        //Do some work
    }
}
+3
source share
3

?

, . , :

class Base { }
class Derived : Base { }

class Foo
{
    void Test()
    {
        Base a = new Base();
        Overload(a);    // prints "base"

        Derived b = new Derived();
        Overload(b);    // prints "derived"

        // dispatched based on c declared type!
        Base c = new Derived();
        Overload(c);    // prints "base"
    }

    void Overload(Base obj)    { Console.WriteLine("base"); }
    void Overload(Derived obj) { Console.WriteLine("derived"); }
}

, , :

class Base
{
    public virtual void Override() { Console.WriteLine("base"); }
}

class Derived : Base
{
    public override void Override() { Console.WriteLine("derived"); }
}

class Foo
{
    void Test()
    {
        Base a = new Base();
        a.Override();   // prints "base"

        Derived b = new Derived();
        b.Override();    // prints "derived"

        // dynamically dispatched based type of object stored in c!
        Base c = new Derived();
        c.Override();    // prints "derived"
    }

    void Overload(Base obj) { Console.WriteLine("base"); }
    void Overload(Derived obj) { Console.WriteLine("derived"); }
}

. #, , this ( " " ). , , .

, .

+4

, , , Control. Draw(), -:

public override void Draw() {
   Button btn = MyControl as Button;
   if (btn != null) {
      Draw(btn);
   } else {
      Draw(this.MyControl);
   }
}

, ""... .

+2

munificent : ++, # . , # , , . , , . , , JIT , .

Since the generated code works for everything that meets the criteria of restrictions, the C # compiler treats your member MyControlas a variable of type Control(not T), since this is as much as can be inferred from the restrictions. Since the compiler must generate general code for the class, it must choose which method to call based on what it knows, and since it cannot be sure whether it will be MyControl Buttonat run time, it must choose Draw(Control).

+2
source

Source: https://habr.com/ru/post/1706120/


All Articles