问题
Can someone tell me why the line with "//Compiles" compiles, and why the line with "//Doesn't Compile" does not?
I don't understand why A would be implicitly convertible to B, not the other way round.
public class SomeClass {
static public void Test() {
AClass a = new AClass();
BClass b = new BClass();
a = b; // Compiles
b = a; // Doesn't compile
}
}
public class AClass {
public void AMethod() {
Console.WriteLine("AMethod");
}
}
public class BClass : AClass {
public void BMethod() {
Console.WriteLine("BMethod");
}
}
thanks!
回答1:
Because B does everything that A does but A does not necessarily do everything that B does. Think of it this way:
AClass --> Shape
BClass --> Circle
Shape a = new Shape();
Circle b = new Circle();
a = b; // works because a is of type "Shape" and a circle is a specific shape
b = a; // doesn't work because b is of type "Circle" and a could be a square.
回答2:
Let's change the name of the classes from AClass to Mammal and BClass to Dog.
a = b; // you're putting a dog on a variable of type Mammal. That's OK.
b = a; // You're putting a mammal (could be a cat, a monkey, etc.) on a variable of type Dog.
Maybe not the best example, but it may be enough for you to understand.
回答3:
This directly follows from the Liskov Substitution Principle:
Let q(x) be a property provable about objects x of type T. Then q(y) should be true for objects y of type S where S is a subtype of T
In other words, the derived class can always be used in place of the base class. It's usually not possibel the other way round - because the base class can't do what the derived class does.
(I know I am mixing up the timeline here - inheritance was first, Liskov came second - but she put nicely how inheritance is intended to be used)
回答4:
An object instantiated from a class may be treated as the type of any of its super-classes, but cannot be treated as the type of a subclass.
- A subclass can be treated as its superclass, but never in the opposite direction.
In more abstract terms:
public class HarleyExample
{
static public void Test()
{
Motorcycle a = new Motorcycle();
HarleyDavidson b = new HarleyDavidson();
Motorcycle c = new Motorcycle(); //Just a plain motorcycle
a = b; // A Harley can be treated as a regular motorcycle
//b = a; // Not just any motorcycle is a Harley
Console.WriteLine("Is A a motorcycle? " + (a is Motorcycle));
Console.WriteLine("Is A a harley? " + (a is HarleyDavidson));
Console.WriteLine();
Console.WriteLine("Is B a motorcycle? " + (b is Motorcycle));
Console.WriteLine("Is B a harley? " + (b is HarleyDavidson));
Console.WriteLine();
Console.WriteLine("Is C a motorcycle? " + (c is Motorcycle));
Console.WriteLine("Is C a harley? " + (c is HarleyDavidson));
Console.ReadKey();
}
}
public class Motorcycle
{
public void Cruise()
{
Console.WriteLine("Cruising");
}
}
public class HarleyDavidson : Motorcycle
{
public void CruiseInStyle()
{
Console.WriteLine("Cruising in style on a Harley");
}
}
回答5:
A is not implicitly convertible to B. B is convertible to A.
In
foo = bar
it's going to try to convert 'bar' to the type of 'foo'.
(That is, I think you are just misinterpreting how 'assignment' works with regards to implicit conversions.)
回答6:
This has little to do with C#; it's basic inheritance. a is not of type BClass. What if BClass had additional fields/properties? What happens when you attempt to access one of those members on a?
回答7:
Because all instances of BClass
are also AClass
since BClass inherits from AClass
. AClass
is less specific than BClass
hence you can implicitly convert from B to A
回答8:
BClass
is a subclass of AClass
(or AClass
is a superclass of BClass
), and the subclass relationship is an "is a" relationship. So if b
is an instance of BClass
, it is also an instance of AClass
. This is why it is fine to point to b
with the variable a
, but it is not OK to point to a
with b
, because that requires an additional assumption.
回答9:
Sort of paraphrasing what everyone else had said. I don't know if this makes it any clearer for you.
'a' is declared as an object of type AClass which supports the AMethod() method.
'b' is declared as an object of type BClass which supports the BMethod() method and, being a subclass of AClass, will also support the AMethod() method as it inherits it from its parent superclass.
So you can easily assign an object of type BClass to a variable of type AClass as the compiler will expect to only ever call AMethod() on it which is fine.
However, you can't assign an object of type AClass to a variable of type BClass as the compiler might expect to have to call either AMethod() or BMethod() on it and, of course, it won't be able to do the latter as an AClass object just won't support it.
回答10:
Possibly you were confused about which was which, as your question asks "Why is implicit conversion allowed from superclass to subclass?".
Actually, it's the other way around. A subclass is an instance of the superclass, but not the other way around, so that's why the types are not compatible.
Imagine a very small superclass with just a single method or constant. Now imagine a subclass that defines everything including a kitchen sink. These are almost completely different types. However, the subclass is still an instance of the superclass; it does have that one method or constant.
The superclass, on the other hand, has almost nothing that the inherited class implements., "Almost" is good enough for the parent to still be an instance of the child class, but passing the parent class to a method expecting the child would most likely not work, as hardly anything is available.
来源:https://stackoverflow.com/questions/1469155/why-is-implicit-conversion-allowed-from-superclass-to-subclass