代码之家  ›  专栏  ›  技术社区  ›  Buda Gavril

使用派生类时的对象类型

  •  0
  • Buda Gavril  · 技术社区  · 7 年前

    具有以下代码:

    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对象?

    2 回复  |  直到 7 年前
        1
  •  2
  •   Damien_The_Unbeliever    7 年前

    你需要区分 编译时类型 (例如,决定调用哪个方法的重载)和 运行时类型 (例如用于反射)。不管你对某个物体做了什么扭曲 (将其转换为基类型等)不会更改对象的运行时类型。

    所以就因为你路过 t Print 它要求 TrxBase ,它没有 改变 t型 变成一个 TrxBase公司 .

    如果,在里面 打印 ,它测试并确定 Trx ,它完全可以将其转换回该类型(隐藏在模式匹配语法中),并开始将其视为真正的类型(当然,它 能够 是一种更源于 Trx公司 .


    额外阅读:埃里克·利珀特的 Representation and Identity


    如果您理解引用更改转换为 新的 反对。这也在上面的奖励阅读中得到了进一步的解释。

        2
  •  1
  •   kuskmen    7 年前

    这就是C#的工作原理,当您使用基类型对象编译器将派生类型对象传递给具有参数的方法时,只需接受该派生对象并将其解释为基对象。

    在您的情况下,您传递的是派生( Trx )对象到方法 TrxBase 参数。所以现在在 Print(TrxBase trx) , trx 会被当作是 TrxBase公司 ,但您正在使用 pattern matching 以确定是否 trx公司 可以转化为更多的派生 Trx公司 对象类型,在您的情况下是真的,可以因此打印 prop 3 .

    可以将派生类型强制转换为更多基类型,但另一种方法将导致 InvalidCastException 来自CLR。因为如果你考虑一下-假设你分配了 TrxBase公司 ,CLR分配器将在堆(如果值类型为堆栈,则为堆栈)上使用此对象所需的所有属性分配此类对象。现在,如果您从CLR请求将这个特定对象强制转换为更特定的对象,那么您最终将请求这个特定的内存布局更改为CLR不支持的另一个(从您的特定对象添加字段、属性等)。