我不太适合使用C#进行投射

时间:2017-12-22 20:33:36

标签: c#

Class A
{
    string name = "a"; 
    public virtual void Rename(){//rename name to aaa}
}

Class B:A
{
    string name = "b";
    public override void Rename(){//rename name to bbb}
}

void Main()
{
    B objB  = new B();
    A objA  = objB as A;
    print(objB.name);// b
    print(objA.name);// a
    objA.Rename();
    print(objB.name);// bbb
    print(objA.name);// a
}

为什么当我使用objA.Rename()时,它实际上使用了在B类中编写的覆盖版本。最后是objA。如果它是A,那么为什么它使用覆盖版本。如果是B,那么为什么objA.name不是bbb;

2 个答案:

答案 0 :(得分:3)

对象永远不会改变。在内存中,无论您选择如何与其进行交互,它始终为B。了解这种情况的方法是只需在变量上调用.GetType(),它们都会告诉您每个变量都是B的实例。

B objB  = new B();
A objA  = objB as A;
Console.WriteLine(objB.GetType()) // B
Console.WriteLine(objA.GetType()) // B

最后获得"a"的原因是因为您有两个不同的声明name。意思是:A.name与<{1}}

完全相同的地址

要解决此问题,您只需从B.name移除string name = "b";,然后将B放入其构造函数中。

name = "b";

考虑这个问题的另一种方法是,如果您在Class A { string name = "a"; public virtual void Rename(){//rename name to aaa} } Class B:A { public override void Rename(){//rename name to bbb} public B() { name = "b"; } } 内拨打base.name,我相信您会得到与B相同的结果,并向您显示"a"实际上有两个单独的B声明。

答案 1 :(得分:0)

首先,您必须了解c#中的转换是一个用于非常不同转换的名称,可能会造成混淆。

您要问的演员在技术上被命名为参考转换。引用转换是保留身份的转换,这意味着对象不会更改,引用的类型会发生什么变化:

var s = “Hello”;
var o = (object)s;
var b = ReferenceEquals(s, o); //returns true

在这里,so指的是完全相同的对象,唯一改变的是引用的类型。

重要的是要注意引用转换是由编译器自动提供的,你不能定义用户定义的身份保留转换,你将得到编译器错误。

您将遇到哪些最常见的参考转换?类型和子类型或类型与实现的接口等之间的任何转换

现在考虑以下看似相似的代码:

var l = 1L;
var i = (int)l;

此代码根本与前一代码不同。为什么?因为此处的演员不是参考转化。这实际上调用了explicit中实现的用户定义的System.Int32强制转换运算符。 il不同的对象。

c#中的另一个重要转换是装箱和拆箱转换。这些不是身份保留,但它们确实共享共同的“功能”,因为无法实现用户定义的装箱或拆箱转换。 Boxing是指将值类型转换为赋值兼容的引用类型,而拆箱是相反的操作:

var i = 1;
var o = (object)i; //boxing
var ii = (int)o; //unboxing

乍一看,你是如何知道它是否是参考转换?好吧,只要你知道所涉及的类型的层次结构。接口等,你应该能够解释它。