C# 在c中转换类的逻辑是什么?

C# 在c中转换类的逻辑是什么?,c#,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

我试图理解一些类的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);
    }
}
在我的主函数中,我调用call 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;
但背后的逻辑是什么?为什么我们不能通过传递一个动物对象来调用函数printAnimalName?根据我的理解,这应该是可能的,因为函数需要动物对象

您的问题在于:

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!
}
强制转换不会调用构造函数。这意味着dog_name为null,因为我的动物没有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);
  }
我还建议将您的公共字段更改为,并且可能是在您想要对对象执行的所有操作都是返回表示该对象的字符串时

之后,var dog1=我的动物是狗;//dog1属于Dog类型,您只需添加空检查:

if(dog1 != null)
{
    Console.WriteLine(dog1.dog_name);
}

我认为您需要了解多态性、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,该方法返回腿数

但是猫有狗没有的仆人,它只有一个朋友,两个人都有,但关系不同。所以狗不需要方法,但猫需要。->两个不同类中的不同实现

接口的另一个例子是,每个派生类都需要提供该功能

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 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...

这是两种用法,您可以派生类并使用铸件来获得某些功能,或者使用basetype而不使用铸件,但仍然获得不同的功能

animal1属于Animal类型,而不是Dog类型。试着把Animal变成一个抽象类,看看会发生什么。您应该像这样使用它:var animal1=新狗;as将尝试使用它,如果无法使用,则返回默认值。如果我的动物是Dog dog1 Console.WriteLinedog1.Dog_name;否则的话,就别想狗了!;对于较新的c,首选铸造通孔。随着你需要施放和测试,随着是你得到的测试包括在内。它将工作,如果你只尝试使用什么是已知的动物,而不是试图施放给狗。如果你需要一只狗,那么这个方法的参数应该是狗而不是动物。你的例子不太好。首先,狗既有狗名又有动物名。第二,如果你想在你的方法中处理一个dog实例,你应该向它传递一个dog实例。如果在方法内部只能使用派生类,则将基类作为参数没有意义。不是dog_name为null,而是dog1为null。您显然不想在此处使用new关键字。如果这样做,当引用是基类类型时,您将获得基类实现。我删除了新的关键字,因为你是对的。将其替换为如何从属性调用字段,因为querant需要开始使用属性。如果传递了另一种类型的属性,为什么这样的方法会失败?除非给它一只狗,否则这个实现将失败。我将回答限制在问题的范围内。这确实是一个问题。如果它不是Dog或派生自Dog,并且没有其他可接受的输入,则将抛出异常。但是,异常处理是根据您需要处理它的位置和方式来完成的,因此它超出了问题的范围。为什么不使用Console.WriteLinedog1?.dog_name;。为您保存一些检查如果需要显示空值,则选择“是”