在c#中编译类的逻辑是什么?

时间:2018-02-15 13:02:47

标签: c#

我试图了解类的一些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对象。

3 个答案:

答案 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属性。我觉得你在这里遗漏了遗产。

这实际上是在现实世界中以更复杂的形式发生的一个例子;鉴于课程AB继承自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(),并返回表示它的字符串。