Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# C转换到基类并使用它的方法_C#_Class_Inheritance_Base - Fatal编程技术网

C# C转换到基类并使用它的方法

C# C转换到基类并使用它的方法,c#,class,inheritance,base,C#,Class,Inheritance,Base,我尝试将一个新变量/对象强制转换到它的基类,但是当我调试时,我注意到它具有派生类的类成员。因此,当我调用一个过度使用的方法时,它调用派生类而不是基类,即使对象被声明为基类 Person person = new Student("Bill", 3.5, "chem"); Console.WriteLine(person.ToString()); .... public class Person { string name; public override strin

我尝试将一个新变量/对象强制转换到它的基类,但是当我调试时,我注意到它具有派生类的类成员。因此,当我调用一个过度使用的方法时,它调用派生类而不是基类,即使对象被声明为基类

Person person = new Student("Bill", 3.5, "chem");
Console.WriteLine(person.ToString());
....
public class Person
{
       string  name;
       public override string ToString() => this.name + " age:" + this.age;
}

public class Student : Person
{
    string major;
    double GPA;
    public override string ToString() => Name + " major:" + major + " GPA: " + GPA;
}
为了解决这个问题,我需要将派生类中的ToString方法定义为new。但我不明白为什么当我在铸造底座时,它应该使用底座方法?这是因为编译器处理引用对象的方式吗?基类的新对象仍然引用派生类内存,而不是将适当的数据复制到它自己的内存块。

是,这称为多态性或运行时多态性。发生这种情况是因为实际类型是Student,即使声明的类型是下面代码行中的person。因此,方法调用发生在实际类型上,而不是声明的类型上

Person person = new Student("Bill", 3.5, "chem");
是的,这就是所谓的多态性或运行时多态性。发生这种情况是因为实际类型是Student,即使声明的类型是下面代码行中的person。因此,方法调用发生在实际类型上,而不是声明的类型上

Person person = new Student("Bill", 3.5, "chem");

有三个关键字需要控制这种行为与polymophism。虚拟、覆盖和新建。这些都得到了很好的解释,如下所示:

覆盖:

重写修饰符可以用于虚拟方法,必须用于抽象方法。这指示编译器使用上次定义的方法实现。即使在对基类的引用上调用该方法,它也将使用覆盖它的实现

新的:

新的修饰符指示编译器使用子类实现而不是父类实现。任何未引用类但父类的代码都将使用父类实现

例如:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BindingExample
{
    public class SomeBaseClass
    {
        public virtual string CustomString() => "From SomeBaseClass";
    }

    public class FirstSpecialisation : SomeBaseClass
    {
        public override string CustomString() => "From FirstSpecialisation";
    }

    public class SecondSpecialisation : SomeBaseClass
    {
        public new string CustomString() => "From SecondSpecialisation";
    }

    class Program
    {
        static void Main(string[] args)
        {
            // Base Example, as expected
            SomeBaseClass a1 = new SomeBaseClass();

            Console.WriteLine(a1.CustomString());

            // First Example, both output the same result
            FirstSpecialisation b1 = new FirstSpecialisation();
            SomeBaseClass b2 = b1;

            Console.WriteLine(b1.CustomString());
            Console.WriteLine(b2.CustomString());

            // Second Example, output different results
            SecondSpecialisation c1 = new SecondSpecialisation();
            SomeBaseClass c2 = c1;

            Console.WriteLine(c1.CustomString());
            Console.WriteLine(c2.CustomString());

            Console.ReadLine();
        }
    }
}
输出:

From SomeBaseClass
From FirstSpecialisation
From FirstSpecialisation
From SecondSpecialisation
From SomeBaseClass
From SomeBaseClassA
From SpecialisationA
From SpecialisationA
From SomeBaseClassB
From SpecialisationB
From SomeBaseClassB
注意第4行和第5行第二专业课的上述行为

这在您的示例中特别有趣,因为您正在重写一个具有2个深度的方法。如果您使用两次overide,则会引发异常行为;表示的最后一个重写优先。因此,必须使用new关键字

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BindingExample
{
    public class SomeBaseClassA
    {
        public override string ToString() => "From SomeBaseClassA";
    }

    public class SpecialisationA : SomeBaseClassA
    {
        public override string ToString() => "From SpecialisationA";
    }

    public class SomeBaseClassB
    {
        public new string ToString() => "From SomeBaseClassB";
    }

    public class SpecialisationB : SomeBaseClassB
    {
        public new string ToString() => "From SpecialisationB";
    }

    class Program
    {
        static void Main(string[] args)
        {
            // First Example
            SomeBaseClassA a1 = new SomeBaseClassA();
            Console.WriteLine(a1);

            SpecialisationA a2 = new SpecialisationA();
            Console.WriteLine(a2);

            SomeBaseClassA a3 = a2;
            Console.WriteLine(a3);

            // Second Example
            SomeBaseClassB b1 = new SomeBaseClassB();
            Console.WriteLine(b1.ToString());

            SpecialisationB b2 = new SpecialisationB();
            Console.WriteLine(b2.ToString());

            SomeBaseClassB b3 = b2;
            Console.WriteLine(b3.ToString());

            Console.ReadLine();
        }
    }
}
输出:

From SomeBaseClass
From FirstSpecialisation
From FirstSpecialisation
From SecondSpecialisation
From SomeBaseClass
From SomeBaseClassA
From SpecialisationA
From SpecialisationA
From SomeBaseClassB
From SpecialisationB
From SomeBaseClassB

当重写ToString方法时,我确实注意到它是在对象上调用的。我假设这是因为Console.WriteLine方法可以接受一个对象,并且因为new关键字用于专门化中的“ToString”方法,所以编译器调用object.ToString。这是你可能希望注意的事情

需要三个关键词来控制这种多毛行为。虚拟、覆盖和新建。这些都得到了很好的解释,如下所示:

覆盖:

重写修饰符可以用于虚拟方法,必须用于抽象方法。这指示编译器使用上次定义的方法实现。即使在对基类的引用上调用该方法,它也将使用覆盖它的实现

新的:

新的修饰符指示编译器使用子类实现而不是父类实现。任何未引用类但父类的代码都将使用父类实现

例如:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BindingExample
{
    public class SomeBaseClass
    {
        public virtual string CustomString() => "From SomeBaseClass";
    }

    public class FirstSpecialisation : SomeBaseClass
    {
        public override string CustomString() => "From FirstSpecialisation";
    }

    public class SecondSpecialisation : SomeBaseClass
    {
        public new string CustomString() => "From SecondSpecialisation";
    }

    class Program
    {
        static void Main(string[] args)
        {
            // Base Example, as expected
            SomeBaseClass a1 = new SomeBaseClass();

            Console.WriteLine(a1.CustomString());

            // First Example, both output the same result
            FirstSpecialisation b1 = new FirstSpecialisation();
            SomeBaseClass b2 = b1;

            Console.WriteLine(b1.CustomString());
            Console.WriteLine(b2.CustomString());

            // Second Example, output different results
            SecondSpecialisation c1 = new SecondSpecialisation();
            SomeBaseClass c2 = c1;

            Console.WriteLine(c1.CustomString());
            Console.WriteLine(c2.CustomString());

            Console.ReadLine();
        }
    }
}
输出:

From SomeBaseClass
From FirstSpecialisation
From FirstSpecialisation
From SecondSpecialisation
From SomeBaseClass
From SomeBaseClassA
From SpecialisationA
From SpecialisationA
From SomeBaseClassB
From SpecialisationB
From SomeBaseClassB
注意第4行和第5行第二专业课的上述行为

这在您的示例中特别有趣,因为您正在重写一个具有2个深度的方法。如果您使用两次overide,则会引发异常行为;表示的最后一个重写优先。因此,必须使用new关键字

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BindingExample
{
    public class SomeBaseClassA
    {
        public override string ToString() => "From SomeBaseClassA";
    }

    public class SpecialisationA : SomeBaseClassA
    {
        public override string ToString() => "From SpecialisationA";
    }

    public class SomeBaseClassB
    {
        public new string ToString() => "From SomeBaseClassB";
    }

    public class SpecialisationB : SomeBaseClassB
    {
        public new string ToString() => "From SpecialisationB";
    }

    class Program
    {
        static void Main(string[] args)
        {
            // First Example
            SomeBaseClassA a1 = new SomeBaseClassA();
            Console.WriteLine(a1);

            SpecialisationA a2 = new SpecialisationA();
            Console.WriteLine(a2);

            SomeBaseClassA a3 = a2;
            Console.WriteLine(a3);

            // Second Example
            SomeBaseClassB b1 = new SomeBaseClassB();
            Console.WriteLine(b1.ToString());

            SpecialisationB b2 = new SpecialisationB();
            Console.WriteLine(b2.ToString());

            SomeBaseClassB b3 = b2;
            Console.WriteLine(b3.ToString());

            Console.ReadLine();
        }
    }
}
输出:

From SomeBaseClass
From FirstSpecialisation
From FirstSpecialisation
From SecondSpecialisation
From SomeBaseClass
From SomeBaseClassA
From SpecialisationA
From SpecialisationA
From SomeBaseClassB
From SpecialisationB
From SomeBaseClassB

当重写ToString方法时,我确实注意到它是在对象上调用的。我假设这是因为Console.WriteLine方法可以接受一个对象,并且因为new关键字用于专门化中的“ToString”方法,所以编译器调用object.ToString。这是你可能希望注意的事情

奇怪的世界。人们知道Lambda表达式的复杂语法,但不知道OOP的第三支柱。真是奇怪的世界奇怪的世界。人们知道Lambda表达式的复杂语法,但不知道OOP的第三支柱。真是奇怪的世界