具有以下代码:
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对象?
答案 0 :(得分:2)
您需要区分编译时间类型(例如,确定要调用的方法的重载类型)和运行时类型(例如,反射使用)。无论您对特定对象 1 进行什么扭曲(将其转换为基本类型,等等)都不会更改该对象的运行时类型。
因此,仅因为您要将t
传递给要求Print
的{{1}},它并不会 change TrxBase
变成t
。
如果在TrxBase
中测试并确定它是Print
,则将其强制转换回该类型(隐藏在模式匹配语法中)并开始处理是完全有效的它确实是一种类型(当然,可以可以是从Trx
派生的类型。
奖金阅读:埃里克·利珀特(Eric Lippert)的Representation and Identity
1 只要您了解引用转换会为您提供 new 对象。上面的奖金阅读中也对此做了进一步解释。
答案 1 :(得分:1)
这是C#的工作原理,当您将派生类型对象传递给具有基本类型对象参数的方法时,编译器只需获取此派生对象并将其解释为基本对象即可。
在您的情况下,您要将派生(Trx
)对象传递给具有TrxBase
参数的方法。因此,现在在Print(TrxBase trx)
的范围内,trx
将被视为TrxBase
,但是随后您使用pattern matching来确定此trx
是否可以表示为更多派生的Trx
对象类型,在您的情况下为true,可以并且因此打印prop 3
。
可以将派生类型转换为更多基本类型,但是另一种方法将导致InvalidCastException
来自CLR。因为如果您考虑一下-假设您分配类型为TrxBase
的新对象,则CLR分配器将在堆(如果值为值类型,则为堆栈)上分配具有该对象具有的所有所需属性的对象。现在,如果您从CLR请求将该特定对象转换为更特定的对象,那么您最终将要求将该特定内存布局更改为CLR不支持的另一种布局(从您的特定对象添加字段,属性等)。