基引用类型与派生引用类型的区别是什么?
本文关键字:引用类型 是什么 区别 派生 | 更新日期: 2023-09-27 18:18:00
class Dog
{
}
class BullDog : Dog
{
}
class Program
{
static void Main()
{
Dog dog2 = new BullDog();
BullDog dog3 = new BullDog();
}
}
使用Dog作为参考和BullDog作为参考有什么区别?
我习惯使用
var dog3 = new BullDog();
,这与BullDog dog2 = new BullDog();
类似。何时需要使用Dog dog2 = new BullDog();
EDIT:解决评论中的其他问题:
static void TakesDog(Dog theDog) { ... }
static void TakesBulldog(Bulldog theBulldog) { ... }
static void TakesObject(object theObject) { ... }
static void Main()
{
//Given these declarations...
object dog = new BullDog();
Dog dog2 = new BullDog();
BullDog dog3 = new BullDog();
//These calls will work because a BullDog is a Dog:
TakesDog(dog2);
TakesDog(dog3);
//this call will work because a Bulldog is a Bulldog:
TakesBulldog(dog3);
//and these calls will ALL work because all Dogs are Objects:
TakesObject(dog);
TakesObject(dog2);
TakesObject(dog3);
//However, these calls will fail because an Object or Dog is not
//necessarily a Bulldog,
//EVEN THOUGH our current dog and dog2 are indeed references to Bulldogs:
TakesBulldog(dog);
TakesBulldog(dog2);
//An explicit conversion is necessary to make the above calls work:
TakesBulldog(dog2 as Bulldog); //works given the current reference
TakesBulldog((Bulldog)dog2); //works given the current reference
TakesBulldog(dog as Bulldog); //ditto
TakesBulldog((Bulldog)dog); //ditto
//but if we change the value of dog2 to some other dog:
dog2 = new Labrador();
//the above calls now fail:
TakesBulldog(dog2 as Bulldog); //passes null into the method
TakesBulldog((Bulldog)dog2); //throws InvalidCastException
//you can avoid problems by checking the true type:
if(dog2 is Bulldog) //interrogates the type of the referenced object
TakesBulldog((Bulldog)dog2); //works
else
TakesDog(dog2); //general fallback case
//Object is similar but even more basic:
dog = "I'm a dog"; //now dog is a System.String
//this call still works:
TakesObject(dog);
//but these will fail:
TakesDog(dog);
TakesBulldog(dog);
}
最后一点要明白:
//given these declarations:
object dog = new BullDog();
BullDog dog2 = new BullDog();
//even though dog is a BullDog, attempting to call BullDog-specific
//members (methods, properties, fields) will fail:
dog.Drool();
//you may only call members as specific as the object type of the
//variable holding the reference:
dog.ToString(); //defined by Object. If you've overridden it in Dog or BullDog,
//you'll get that implementation
dog2.Drool(); //works because we know from the variable that dog2 is a BullDog.
使用基类型作为引用类型时,只能调用在基类型上定义的成员。为了使用超类型的成员,需要进行强制类型转换。
因此,如果BullDog
定义了DoNotRelease
方法,则不能直接从Dog
引用调用它。
对于var
-,它将推断出更具体的类型。因此,如果使用new BullDog()
,则推断类型将是BullDog
。
通常在使用继承时也会使用重载。
但是考虑以下内容:
static void Main()
{
Dog dog = new BullDog();
BullDog bulldog = new BullDog();
dog.Execute();
bulldog.Execute();
}
class Dog
{
public virtual void Execute()
{
Console.WriteLine("Execute Dog");
}
}
class BullDog : Dog
{
public new void Execute() // use new instead of override
{
Console.WriteLine("Execute BullDog");
}
}
这将打印:
Execute Dog
Execute BullDog
如果要访问仅对该类型可用的函数,则需要定义子类型。如果你想使用操作符重载(使用覆盖操作符),你可以使用这个子类的行为,而不用担心当前的类型。
——编辑——
你问的是:
object a3 = new BullDog();
BullDog a3 = new BullDog();
对于初学者来说,在相同的作用域中,这会给你一个编译错误,因为a3不能被定义两次。但是假设你在不同的范围内定义它们。
在对象a3上,你只能调用对象(Equals, GetHashCode, ToString, GetType())上可用的方法。如果你想在它上面使用只在Dog类中可用的方法,你必须将它强制转换为Dog。
object a3 = new BullDog();
BullDog a4 = new BullDog();
if (a3 is Dog)
{
// only executes when a3 is a Dog
// a3 is for the compiler still of type object, so you can't call any other methods on it
}
Dog d1 = a3 as Dog; // cast it to a dog
if (d1 != null) // if d1 == null, then a3 was not of type dog and the cast returned null
{
d1.Execute(); // we know now that d1 is a dog and that it points to a dog instance so we can call a dog method on it.
}
a4.Execute();
您不需要Dog dog2 = new BullDog()
,您将能够将BullDog
传递给任何期望Dog
的方法。
看看http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming
让我们定义另一个类:
class OtherDog : Dog
{
}
现在你可以这样定义一个列表:
c#:
List<Dog> Dogs = new List<Dog>();
Dogs.Add(new BullDog());
Dogs.Add(new OtherDog());
你有一个Dog类型的列表,但是可以添加BullDog和OtherDog类型的列表
这是其中一个名为"多态性"的OOP主题
ex2:
让我们假设你想要开发一种油漆:
class Shape ()
{
virtual public void Draw()
{
}
}
class Rectangle : Shape ()
{
override public void Draw()
{
}
}
class Circle : Shape ()
{
override public void Draw()
{
}
}
void main ()
{
List<Shape> Shapes = new List<Shape>();
Shapes.Add(new Rectangle());
Shapes.Add(new Circle());
Shape[1].Draw(); //Draw a rectangle
Shape[2].Draw(); // Draw a circle
}
如果你需要更多的细节,请评论我编辑我的回复以获得更多的细节
谢谢你,Ali
问:"使用Dog作为引用与使用BullDog作为引用有什么区别?"
A:如果你有一个Dog引用,你添加到派生类型BullDog的任何额外的方法/属性/字段将不能被公开访问。
。如果你有:
public class Dog
{
public virtual void Bark()
{
Console.WriteLine("Woof");
}
}
public class BullDog : Dog
{
public override void Bark()
{
Console.WriteLine("BOWF!");
}
public void Slobber()
{
Console.WriteLine("I cannot control my drool :(");
}
{
…你不能这样做:
Dog baseDog = new BullDog();
baseDog.Slobber(); // error -- Dog doesn't know how to slobber.
…因为基类型不存在该方法。
同样,如果不小心使用new操作符,还会出现一些微妙的问题,这取决于您是否有基/派生引用。然而,这些在我的经验中是非常罕见的(见Wouter de Kort的帖子,因为他在我打字的时候发布了一个更好的解释)。
Q:"我习惯使用var dog3 = new BullDog();类似于BullDog dog2 = new BullDog();什么时候我们需要使用Dog dog2 = new BullDog();?"
A:你可能甚至不知道你得到的是什么类型的Dog
,你所知道的就是…这是Dog
。考虑……public static class DogFactory
{
public static Dog CreateMysteryDog()
{
return new Shitzu();
}
}
Dog dog = DogFactory.CreateMysteryDog(); // what is the concrete type of Dog?
DogFactory返回Dog
引用,而不是Shitzu
引用,所以你必须使用基类型。在这种情况下,var也将是Dog
而不是Shitzu
。