为什么c#在向上转换后将实例中先前非空的成员视为空?
本文关键字:成员 转换 实例 为什么 | 更新日期: 2023-09-27 18:16:28
在开发一个通过JSON与外部数据库通信的类库时,出现了一个有趣的问题:对象实例的上转换导致其先前的非空成员之一显示为空。
为了找出这个奇怪现象的原因,我已经绞尽脑汁了,但到目前为止,我还没能找到一个合理的解释。
下面是这个问题的一个例子:
using System;
namespace Test
{
public class Program
{
static void Main(string[] args)
{
Descendant d = new Descendant();
d.Attributes.ToString(); // Everything fine here
Ancestor a = (Ancestor)d;
a.Attributes.ToString(); // NullPointerException
}
}
class Ancestor
{
public interface IAttributes { }
public IAttributes Attributes;
}
class Descendant : Ancestor
{
public new DescendantAttributes Attributes;
public Descendant()
{
this.Attributes = new DescendantAttributes();
}
public class DescendantAttributes : IAttributes
{
public string Name = "";
}
}
}
错误信息:System。在Test.Program中未处理NullReferenceException。Main(String[] args) in D:'Code'c#'Test'Program.cs:line 12
。NET版本:4.0
环境:64位Windows 2008 R2, Visual Studio 2010
为什么会发生?我的意思是,除非它是一个bug,否则它背后可能有一个设计原理。在哪种情况下CLR会在向上转换之后将实例的先前非空成员视为空?
当您使用new
修饰符时,您将隐藏继承的属性。
public new DescendantAttributes Attributes;
看下面的链接http://msdn.microsoft.com/en-us/library/vstudio/435f1dw2.aspx
When used as a modifier, the new keyword explicitly hides a member that's inherited from a
base class. When you hide an inherited member, the derived version of the member replaces the
base-class version. You can hide members without using the new modifier, but the result is a
warning. If you use new to explicitly hide a member, the modifier suppresses this warning and
documents the fact that the derived version is intended as a replacement.
在C#
中,new
关键字可以用作操作符、修饰符或约束。MSDN链接
- new operator:用于在堆上创建对象并调用构造函数。
- new修饰符:用于隐藏基类成员的继承成员。
- new constraint:用于限制可能用作泛型声明中类型形参参数的类型。
您在这里使用new作为修饰符
new modifier
用于显式隐藏从基类继承的成员。在您的代码中,您正在跟踪Attributes
,它在该层次结构级别提供了不同的实现。正如Dirk所说,你正在创建一个新的不相关的属性
class Ancestor
{
public interface IAttributes { }
public IAttributes Attributes;
}
class Descendant : Ancestor
{
public new DescendantAttributes Attributes; //Shadowing using new modifier
public Descendant()
{
this.Attributes = new DescendantAttributes();
}
public class DescendantAttributes : IAttributes
{
public string Name = "";
}
}
您需要的不是shadowing
,而是overriding
-
class Ancestor
{
public interface IAttributes { }
public virtual IAttributes Attributes { get; set; } // Make this virtual
}
class Descendant : Ancestor
{
// Override here OR instead you can omit the declaration at all.
public override IAttributes Attributes { get; set; }
public Descendant()
{
this.Attributes = new DescendantAttributes();
}
public class DescendantAttributes : IAttributes
{
public string Name = "";
}
}
From this post -
假设您有一个基类,并且您在所有的代码而不是继承的类,并且您使用影子,它将返回基类返回的值,而不是跟随对象实类型的继承树。