我试图了解类的一些C#转换条件背后的逻辑,这是我的测试代码
文件:example.cs
public class Animal { public string animal_name = "Animal"; }
public class Dog : Animal { public string dog_name = "Dog"; }
public class Class1
{
public void createObjects()
{
var animal1 = new Animal();
printAnimalName(animal1);
}
public void printAnimalName(Animal my_animal)
{
var dog1 = my_animal as Dog; // dog1 is of type Dog
Console.WriteLine(dog1.dog_name);
}
}
在我的Main函数中,我调用createObjects函数调用如下:
static void Main(string[] args)
{
Class1 c1 = new Class1();
c1.createObjects();
Console.ReadLine();
}
运行上面的代码会出错
System.NullReferenceException:'Object reference not set to an instance of an object'
我知道这是应该的方式,因为投射:
var dog1 = my_animal as Dog;
但它背后的逻辑是什么?为什么我们不能通过为它传递Animal对象来调用函数printAnimalName?根据我的理解,这应该是可能的,因为该函数需要一个Animal对象。
答案 0 :(得分:3)
在var dog1 = my_animal as Dog; // dog1 is of type Dog
之后,你只需要添加空检查:
if(dog1 != null)
{
Console.WriteLine(dog1.dog_name);
}
答案 1 :(得分:1)
我认为您需要了解多态性,abscract类和接口。
public abstract class FourLeggedAnimal
{
public int GetLegCount()
{
return 4;
}
}
public class Dog : FourLeggedAnimal
{
public string GetScientificName()
{
return "doggus scientificus";
}
}
public class Cat : FourLeggedAnimal
{
public string GetServant()
{
return "human";
}
}
public class AnimalInformer
{
public void DisplayInformation(FourLeggedAnimal animal)
{
Console.WriteLine("It has {0} legs", animal.GetLegCount());
if (animal is Dog)
Console.WriteLine("Its scientific name is {0}", ((Dog)animal).GetScientificName());
if (animal is Cat)
Console.WriteLine("Its servant is {0}", ((Cat)animal).GetServant());
}
}
在这里,您使用absract类为从其派生的所有其他类提供基本功能。从FourLeggedAnimal
派生的所有类都有一个返回腿数的方法GetLegCount()
。
但是一只猫有一只狗没有的仆人,它只有一个朋友(人类,但不同的关系)。所以狗不需要任何方法" GetServant"但猫呢。 - >在2个单独的类中区分实现
接口的另一个例子是每个派生类都需要提供该功能。
public interface IMovableObject
{
int GetMaxSpeed();
}
public class Car : IMovableObject
{
public int GetMaxSpeed()
{
return 100;
}
}
public class Human : IMovableObject
{
public int GetMaxSpeed()
{
return 20;
}
}
public static class SpeedChecker
{
public static void CheckSpeed(IMovableObject speedster)
{
Console.WriteLine("Checking Speed..");
int speed = speedster.GetMaxSpeed();
if (speed > 50)
Console.WriteLine("It's really fast!");
else
Console.WriteLine("Just a turtle or something similar...");
}
}
现在,如果你有一个方法获得一个实际上是汽车的IMovableObject,你可以调用Car的实现:
Car c = new Car();
Human h = new Human();
Console.WriteLine("Checking Car..");
SpeedChecker.CheckSpeed(c);
Console.WriteLine("Checking Human..");
SpeedChecker.CheckSpeed(h);
- >返回:
Checking Car...
Checking Speed...
It's really fast!
Checking Human...
Checking Speed...
Just a turtle or something similar...
这些是2种用途,您可以在这些用途中派生类并使用cast来获取某些功能,或者使用basetype而不进行强制转换但仍然可以获得不同的功能
答案 2 :(得分:0)
你的问题在这里:
public void printAnimalName(Animal my_animal)
{
var dog1 = my_animal as Dog; // dog1 is of type Dog
Console.WriteLine(dog1.dog_name); //Animal does not have this property!
}
Casting不会调用构造函数。这意味着dog_name
为空,因为my_animal
没有dog_name
属性。我觉得你在这里遗漏了遗产。
这实际上是在现实世界中以更复杂的形式发生的一个例子;鉴于课程A
,B
继承自A
。由于继承,两者都具有相同的属性。然后有人使用类似但不一致的属性名称创建不同的属性,并将其用于子对象中的相同函数。欢迎来到代码闻闻城市。
要修复你的功能以便它像狗一样,你要做两件事:
public class Animal { public string animal_name = "Animal"; }
//since we want a different default, we can
//can make the change in the constructor
public class Dog : Animal
{
Dog(){ this.animal_name = "Dog"; }
//if you really, really want a second name string, you can do this:
public string Dog_Name
{
get { return this.animal_name; }
set { this.animal_name = value; }
}
}
然后,您需要让您的方法调用适当的属性。
public void printAnimalName(Animal my_animal)
{
var dog1 = my_animal as Dog; // dog1 is of type Dog
Console.WriteLine(dog1.animal_name);
}
我还建议您将所有想要处理对象的公共字段更改为properties,并可能override ToString(),并返回表示它的字符串。