c#使用派生类时的对象类型

具有以下代码:


class TrxBase

{

    public string Prop1 { get; set; }

    public string Prop2 { get; set; }

}

class Trx : TrxBase

{

    public string Prop3 { get; set; }

}


    static void Print(TrxBase trx)

    {

        if (trx is Trx trx1)

        {

            Console.WriteLine(trx1.Prop3);

        }

        else

        {

            Console.WriteLine("no match");

        }

    }


    static void Main(string[] args)

    {

        Trx t = new Trx();

        t.Prop1 = "prop 1";

        t.Prop3 = "prop 3";


        Print(t);

    }

上面的代码打印“prop 3”。据我所知。在 Print 方法中,该对象将作为 TrxBase 读取。如果是这种情况,Prop3 属性保存在哪里?程序如何知道我的参数实际上是一个 Trx 对象?


萧十郎
浏览 274回答 2
2回答

繁花不似锦

您需要区分编译时类型(例如确定调用方法的哪个重载的那些)和运行时类型(例如反射使用的那些)。无论您对特定对象1 进行何种扭曲(将其转换为基类型等)都不会更改对象的运行时类型。所以,仅仅因为你传递t给Print它要求一个TrxBase,它不会改变 t成TrxBase。如果在 inside 中Print测试并确定它是 a Trx,则将其强制转换回该类型(隐藏在模式匹配语法中)并开始将其视为真正的类型(当然,尽管,它可能是一种更源自Trx.额外阅读:埃里克·利珀特的代表和身份1如果您了解引用更改转换为您提供了一个新对象。这在上面的奖励阅读中也有进一步的解释。

心有法竹

这就是 C# 的工作方式,当您将派生类型对象传递给具有基类型对象参数的方法时,编译器只需获取此派生对象并将其解释为基类。在您的情况下,您将派生 ( Trx) 对象传递给带有TrxBase参数的方法。因此,现在在 的范围内Print(TrxBase trx),trx将被视为TrxBase, 但随后您将使用模式匹配来确定这是否trx可以表示为更派生的Trx对象类型,在您的情况下是正确的,因此可以打印prop 3。可以将派生类型转换为更多基类型,但另一种方式将导致InvalidCastException来自 CLR。因为如果您考虑一下 - 假设您分配类型为的新对象TrxBase,CLR 分配器将在堆(或堆栈,如果值类型)上分配此类对象,并具有该对象具有的所有所需属性。现在,如果您从 CLR 请求将此特定对象转换为更具体的对象,您最终会请求将此特定内存布局更改为 CLR 不支持的另一个(从您的特定对象添加字段、属性等)。
打开App,查看更多内容
随时随地看视频慕课网APP