Home > database >  What is the explanation of this Cast to Generic behaviour?
What is the explanation of this Cast to Generic behaviour?

Time:11-10

public interface IBaseUiItem
{}

public interface IButton : IBaseUiItem
{}

public class ControlBase : IBaseUiItem
{}

public class Button : ControlBase, IButton
{}

public I GetOne<I>() where I : IBaseUiItem
{
     return (I)(new Button());
}

public I GetTwo<I>() where I : IBaseUiItem
{
     object f = new Button();
     return (I)f;
}

In the above why GetOne() doesn't compile, but the GetTwo() does? In other words why the error in the first case is "Connot convert type Button to I"

I tried using "as" operator to see if it makes difference (without luck of course).
I guess, the GetOne cannot be compiled because saves you from a creation of an instance (new Button) that might not implement the interface type you supply to the method.
And also I understand the "object" being so general makes it a possible candidate for casting to any type.
And finally, the fact that there is no special interface-obtaining-operator doesn't allow the compiler to make proper usage of the generic, no matter if it is an "interface generic" and not "type generic".

CodePudding user response:

In other words why the error in the first case is "Cannot convert type Button to I"

Because I is not guaranteed to be Button (or any interface which inherits IBaseUiItem and is implemented by Button) i.e. compiler prevents calls such as:

public class NotAButton : ControlBase, IButton {}

var x = GetOne<NotAButton>();

using object as intermediate type disables this compiler check (as explicit conversion from object and dynamic to any other reference_type) and you will get runtime error:

GetTwo<NotAButton>();

System.InvalidCastException: Unable to cast object of type 'Button' to type 'NotAButton'.

If you want to be able to create a new instance of your generic you can use new generic constraint:

I GetOne<I>() where I : IBaseUiItem, new()
{
     return new();
}
  • Related