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;
答案 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
在这里,s
和o
指的是完全相同的对象,唯一改变的是引用的类型。
重要的是要注意引用转换是由编译器自动提供的,你不能定义用户定义的身份保留转换,你将得到编译器错误。
您将遇到哪些最常见的参考转换?类型和子类型或类型与实现的接口等之间的任何转换
现在考虑以下看似相似的代码:
var l = 1L;
var i = (int)l;
此代码根本与前一代码不同。为什么?因为此处的演员不是参考转化。这实际上调用了explicit
中实现的用户定义的System.Int32
强制转换运算符。 i
和l
是不同的对象。
c#中的另一个重要转换是装箱和拆箱转换。这些不是身份保留,但它们确实共享共同的“功能”,因为无法实现用户定义的装箱或拆箱转换。 Boxing是指将值类型转换为赋值兼容的引用类型,而拆箱是相反的操作:
var i = 1;
var o = (object)i; //boxing
var ii = (int)o; //unboxing
乍一看,你是如何知道它是否是参考转换?好吧,只要你知道所涉及的类型的层次结构。接口等,你应该能够解释它。