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的第三支柱。真是奇怪的世界