Casting from a base class to a derived class
2009-02-16 17:44
302 查看
Casting from a base class to a derived class
Antonio Bello posted on September 27, 2008 05:23This morning a friend of mine asked me how to cast a generic list to a custom class inherited from the generic list.
Let’s suppose we have the following class:
view plaincopy to clipboardprint?
public class MyClass
{
...
}
public class MyClass { ... }
and we need a collection of instances of this class, for example using the generic List<> class
view plaincopy to clipboardprint?
List<MyClass> myCollection;
List<MyClass> myCollection;
In order to improve readability, but also save time when writing code, we are often tempted to create a non-generic class implementing the list we need – even if we usually don’t really need such class
view plaincopy to clipboardprint?
public class MyCollection : List<MyClass>
{
}
public class MyCollection : List<MyClass> { }
The problem arises when we use both the generic version and the custom version of the list in our code, and more specifically when we create an instance using the generic list and we need to pass this instance to a method expecting the custom version of the list:
view plaincopy to clipboardprint?
// This is the method we need to call
public void DoSomething(MyCollection myCollection)
{
...
}
List<MyClass> myClass = new List<MyClass>();
DoSomething(myClass); // This doesn't work
// This is the method we need to call public void DoSomething(MyCollection myCollection) { ... } List<MyClass> myClass = new List<MyClass>(); DoSomething(myClass); // This doesn't work
The code above generates an error during compilation, whereas a direct cast from List<MyClass> to MyCollection generates a runtime exception:
view plaincopy to clipboardprint?
List<MyClass> myList;
MyCollection myCollection;
myList = new List<MyClass>();
myCollection = (MyCollection) myList; // This generates a runtime exception
List<MyClass> myList; MyCollection myCollection; myList = new List<MyClass>(); myCollection = (MyCollection) myList; // This generates a runtime exception
The problem is that List<MyClass> is a base class and MyCollection is a derived class, hence there is no way to explicitly perform the cast.
Let’s forget about lists and generics for a moment. We have to classes:
view plaincopy to clipboardprint?
public class MyBaseClass
{
...
}
public class MyDerivedClass : MyBaseClass
{
...
}
public class MyBaseClass { ... } public class MyDerivedClass : MyBaseClass { ... }
If I write the following code:
view plaincopy to clipboardprint?
MyBaseClass myBaseClass;
MyDerivedClass myDerivedClass;
myBaseClass = new MyBaseClass();
myDerivedClass = (MyDerivedClass) myBaseClass; // This generates a runtime exception
MyBaseClass myBaseClass; MyDerivedClass myDerivedClass; myBaseClass = new MyBaseClass(); myDerivedClass = (MyDerivedClass) myBaseClass; // This generates a runtime exception
The last statement obviously causes a runtime exception, as a downcast from a base class to a derived class cannot be done.
Unhandled Exception: System.InvalidCastException: Unable to cast object of type 'MyBaseClass' to type 'MyDerivedClass'. at Program.Main()
The reason is that a derived class (usually) extends the base class by adding more state objects (i.e. data members). When we create an instance of a base class, its data members are allocated in the memory, but of course data members of inherited classes are not allocated. So, downcasting from a base to a derived class is not possible because data members of the inherited class are not allocated.
But if we instantiate MyBaseClass as MyDerivedClass the cast is allowed – in other words downcasting is allowed only when the object to be cast is of the same type it’s being cast to:
view plaincopy to clipboardprint?
myBaseClass = new MyDerivedClass(); myDerivedClass = (MyDerivedClass) myBaseClass;
myBaseClass = new MyDerivedClass(); myDerivedClass = (MyDerivedClass) myBaseClass;
This because myBaseClass, although being a variable of type MyBaseClass, is a reference to an instance of MyDerivedClass.
In our problem, MyBaseClass is List<MyClass> and MyDerivedClass is MyCollection, so we are trying to cast an instance of a base class to an instance of a derived class. It’s evident why the cast we want to do is not allowed.
So, is there a solution? If we think in terms of casting, the answer is NO. What we can do is a conversion.
The difference between cast and conversion is that the cast operates on the same object instance, whereas a conversion creates a new copy.
We might think about implementing a conversion operator, either implicit or explicit, for instance:
view plaincopy to clipboardprint?
public class MyCollection : List<MyClass>
{
public static implicit operator MyCollection(List<MyClass> myClass)
{
...
}
...
}
public class MyCollection : List<MyClass> { public static implicit operator MyCollection(List<MyClass> myClass) { ... } ... }
but it won’t work, as the compiler generates a CS0553 error
'conversion routine' : user defined conversion to/from base class
User-defined conversions to values of a base class are not allowed; you do not need such an operator
The reason why the compiler denies such conversion is that the explicit cast operator from a base to an derived class is automatically generated, and we can’t override it with a new conversion operator.
The only viable solutions are either defining a copy constructor or implementing a method in the derived class which converts the base class to an instance of the derived class:
view plaincopy to clipboardprint?
public class MyCollection : List<MyClass>
{
// Copy constructor
public MyCollection(List<MyClass> myList) : base (myList)
{
...
}
// Conversion method
public static MyCollection ToMyCollection(List<MyClass> myList)
{
...
}
}
In both cases, anyway, the conversion implies the creation of a new instance of the object to be converted.
相关文章推荐
- How can I protect derived classes from breaking when I change the internal parts of the base class?
- 类学习之Use Base keyword to call method in parent class from subclass
- tried to access method com.google.common.base.Stopwatch.<init>()V from class org.apache.hadoop.ma...
- javax.jms.JMSException: Failed to build body from content. Serializable class not available to broke
- hibernate class cast exception from object to ...
- 精彩控件件源码(3)-ImageListPopup, a C# class which pops up a window to select an image from an image list
- 关于An association from the table refers to an unmapped class
- SoapClientBase ,A Good Class provide a mean to WebServices
- From N to N+1: Multiclass Transfer Incremental Learning 代码分析(1)
- Unable to find a single main class from the following candidates
- Unable to find a single main class from the following candidates
- java.base/jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to java.base/java.net.URLCl
- Maven使用package打包Spring Boot时出现:Unable to find a single main class from the following candidates的问题解决
- 关于An association from the table refers to an unmapped class
- c# - Composite from two base classses
- Failed to load Main-Class manifest attribute from
- A class to grab pictures from your camera
- 运行jar 提示 Failed to load Main-Class manifest attribute from
- My.Class.IO.DirOperate.CopyDir(string strFromDirectory, string strToDirectory)
- What happens when more restrictive access is given to a derived class method in C++?