NullReferenceException从基类引用派生成员对象的公共成员

时间:2012-09-26 10:17:07

标签: c# .net polymorphism base derived

由于这是我的第一篇StackOverflow帖子,我想简单地说一下 huge ,感谢那些管理网站的人和那些积极向他人提供帮助的人。 StackOverflow是解决C#代码挑战的一个非常有用的资源。

类描述:在MS VisualStudio 2010 C#.NET控制台应用程序中,我有以下基本/派生层次结构:

  • Entry - > DirEntry
  • Entry - > FileEntry - > AudioFileEntry - > OutputFileEntry

......后三者分别是以下基础/派生层次结构中的成员:

  • Directory - > AudioDirectory - > OutputDirectory

......这样:

  • Directory有成员public FileEntry[] file_entries;
  • AudioDirectory有成员public AudioFileEntry[] file_entries;
  • OutputDirectory有成员public OutputFileEntry[] file_entries;

基类Entry以下列方式声明:

public class Entry : IComparable
{
    public string name;
    public int entryID;
    public int parentID;
    //(other code omitted)
}

Directory也有成员公开DirEntry[] dir_entries;没有问题,但请注意DirEntry不会超过Directory(没有AudioDirEntry ,例如)。

问题: NullReferenceException尝试从基类file_entries[n]方法或其他类中读取Directory内的常见成员当类型为AudioDirectoryOutputDirectory时。

没有相关的类,成员或方法是静态的。我尝试使用newoverride无济于事。试图让file_entries属性:

public class Directory
{
    public virtual FileEntry[] file_entries { get; set; }
}

public class AudioDirectory : Directory
{
    public override AudioFileEntry[] file_entries { get; set; }
    //(other code omitted)
}

...因错误“... 'app1.AudioDirectory.file_entries': type must be 'app1.FileEntry[]' to match overridden member 'app1.Directory.file_entries'

而失败

目标:能够在基类file_entries方法中引用Directory,无论该对象是哪种派生类型。我的直觉告诉我,我可能忽略了一些简单的事情,因为上面基本上是多态性的全部内容,并且 应该成为一种方法来实现这一点,而不需要求助于新的dynamic类型

建议?

-Turbine

2 个答案:

答案 0 :(得分:3)

您的问题是,当您覆盖属性或方法时,您无法更改签名,即所涉及的类型。您可以使用new修饰符忽略此限制,但您必须非常清楚这意味着什么(稍后将详细介绍)。在您的情况下,您必须避免在子类中隐式定义属性,因为这将在子类中声明一个与基类中的新变量不同的新变量。我的意思是你的代码与此相同:

public class Directory
{
    private FileEntry[] _file_entries;
    public virtual FileEntry[] file_entries 
    {
        get { return _file_entries; }
        set{_file_entries = value;} 
    }
}

public class AudioDirectory
{
    private AudioFileEntry[] _sub_file_entries;
    public new AudioFileEntry[] file_entries 
    {
        get { return _sub_file_entries; }
        set{_sub_file_entries = value;} 
    }
}

这意味着当您在AudioDirectory中设置file_entries时,在基类中访问的变量仍为空。

可能的解决方案是:

public class Directory
{
    private FileEntry[] _file_entries;
    public virtual FileEntry[] file_entries 
    {
        get { return _file_entries; }
        set{_file_entries = value;} 
    }
}

public class AudioDirectory : Directory
{
    public new AudioFileEntry[] file_entries
    {
        get { return (AudioFileEntry[])base.file_entries; }
        set { base.file_entries = value; }
    }
}

这应该有效,但要小心使用new修饰符强制编译时绑定,这意味着执行的属性取决于声明的变量的类型,而不是实例的实际错误。例如,在下面的代码中,您有一个AudioDirectory实例,但第一次调用file_entries执行AudioDirectory版本,第二次调用Directory目录:

        AudioDirectory ad = new AudioDirectory();
        Directory d = ad;

        FileEntry[] fa = ad.file_entries;
        FileEntry[] fb = d.file_entries;

答案 1 :(得分:0)

  

“'app1.AudioDirectory.file_entries':type必须是'app1.FileEntry []'才能   匹配重写成员'app1.Directory.file_entries'“

表示您需要返回从基类覆盖的相同类型:

public class Directory
{
    public virtual FileEntry[] file_entries { get; set; }
}

public class AudioDirectory : Directory
{
    public override FileEntry[] file_entries { 
        get 
        {
           return new AudioFileEntry[] { new AudioFileEntry() };
        }
        set 
        {
           //(other code omitted)
        } 
    }
}

如果您有其他问题,请提供您的所有代码。