Upcasting 如何保留派生的 类 的属性?

How Upcasting preserve derived classes's Properties?

        static void Main(string[] args)
        {
            Student student = new Student()
            {
                ID = 12,
                Name = "Manu",
                LastName = "Shekar"
            };

            Iregister x = student;
            Student newstudent = x as Student;

           //Console.WriteLine(x.LastName); //Uncommenting this shows compilation error
            Console.WriteLine(newstudent.LastName); //This Show "Shekar"
            Console.ReadKey();

        }


    class Student : Iregister
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public String LastName { get; set; }

    }
    interface Iregister
    {
        int ID { get; set; }
        String Name { get; set; }


    }

我想知道 newstudent.LastName 是如何从没有 LastName 属性 的 Iregister 中转换而来的正确值? 值 "Shekar" 如何从 student.LastName 传递到 newstudent.LastNamex 是否将其存储在两者之间?如果我错过了一些基础知识,请原谅我。

I wonder how the newstudent.LastName gets the correct value since it is casted from Iregister which doesn't have LastName property?

事实是 x 是一个类型 Iregister 但它 指向 一个 Student 对象因此一旦转换你就可以访问 Student 字段。

当直接使用x时,编译器只允许你选择定义在IRegister类型上的成员,因为x就是那个类型。将 x 转换为 Student 后,编译器允许您使用 Student 的任何成员,因为 newstudent 变量的类型为 Student.

您创建了一个 对象 ,并在变量 student 中分配了对它的引用。

然后您为同一对象创建第二个 引用,并将其分配给 xxstudent 都引用同一个对象,但是 x 变量的类型意味着只有在 IRegister 上定义的成员可用。

然后您创建对同一对象的第三个引用并将其分配给 newstudent。由于 newstudentStudent 类型,您可以从该引用访问 Student 的所有成员。

并不是说变量只是存储引用。是对象存储了它自己的实际数据,并且那个对象在整个过程中保持不变。

How Interface stores inherited class's Property

接口不存储值。它们仅确保实现接口的 类 中某些属性和方法的可用性。

I wonder how the newstudent.LastName gets the correct value since it is casted from Iregister which doesn't have LastName property?

向下转换对象不会更改对象的类型,只会更改您正在使用的变量的类型。

public interface IMyInterface
{
    String Name { get; }
}

public class BaseType : IMyInterface
{
    public virtual String Name
    {
        get { return "Base Name"; }
    }
}

public class DerivedType : BaseType
{
    public override String Name
    {
        get { return "Derived Name"; }
    }
}

然后我在 C# Interactive window 中测试了以下命令:

var derived = new DerivedType();

IMyInterface derivedAsInterface = derived;
BaseType derivedAsBaseType = derived;

derived.Name                //returns "Derived Name"
derivedAsInterface.Name     //returns "Derived Name"
derivedAsBaseType.Name      //returns "Derived Name"

如您所见,每当您请求 Name 属性 时,该对象的行为仍然与 DerivedType 相同,因为这就是该对象。

这是因为 类 本质上是 引用类型 。对于 值类型 (例如 floatint),这确实有所不同,但这与值类型和引用类型之间的内在差异有关。
如果您想知道原因,请继续阅读 the difference between value and reference types in C#


仔细想想,你的假设是不合理的。在我的代码示例中,我有三个独立的变量:derivedderivedAsInterfacederivedAsBaseType。这些都指向内存中的同一个对象。

这在逻辑上意味着同一个对象必须兼容所有三个变量,否则无法在需要时使用所有这些变量。

  • 如果将对象更改为 IMyInterface 类型的对象,那么我的变量 derivedAsBaseTypederived 将不再正常运行。
  • 如果将对象更改为 BaseType 类型的对象,那么我的变量 derived 将不再正常运行。
  • 唯一剩下的解释是我的对象始终保持其原始类型 (DerivedType),因为这是保持与所有三个变量兼容的唯一方式。

如果您不明白为什么它们在内存中引用同一个对象,您应该继续阅读 the difference between value and reference types in C#。这个主题太宽泛了,无法在 Whosebug 上找到答案。