繁体   English   中英

初学者:扩展C#中的类,我做错了吗?

[英]Beginner: Extending a class in C#, am I doing it wrong?

同样, 免责声明免责声明通常仍在学习C#和OOP,所以希望您对我耐心:)

我目前正在使用一个具有FileVersion类的CMS,该类基本上包含与文件有关的属性列表,例如文件名,文件类型,字节大小,id,上载日期,最新版本等。

FileVersion的列表包含在具有自己唯一ID的File中。 当您要从CMS下载特定文件时,将使用以下内容构建URL:

string URL = "/files/"+file.id.toString()+"/"+file.fileVersion.Last().filename;

现在,对于我正在处理的特定控件(专门处理作为文档的文件),能够将URL与所有其他FileVersion信息一起存储以备后用是很有意义的。 因此,我决定要做的是创建自己的名为DocumentVersion的类,该类扩展了FileVersion 看起来是这样的:

public partial class DocumentVersion : FileVersion
{
    public DocumentVersion() : base() { }
    public string link;
}

现在我应该注意,看来我不需要在这里实现接口了-但是不要以为福音,这就是为什么我在这里。

但是,当我尝试将FileVersionDocumentVersion如下所示:

DocumentVersion dv = ((DocumentVersion)fileversion);

我得到以下异常:

无法将类型为“ Foo.CMS.FileVersion”的对象转换为类型为“ CoA.DocumentVersion”的对象。

我的暗示是,因为我试图在与原始位置不同的命名空间中扩展类,但是就像我说的那样,OOP对我而言相对较新,所以我可能是错的。

在此先感谢您的帮助。 这个社区是如此宝贵! 我只是希望一旦我变得更加熟练,我就可以回馈:)。

您是否要垂头丧气? 即采用现有的FileVersion并将其声明为DocumentVersion

如果是这样,您将无法执行此操作,因为您所拥有的不过是FileVersion

相反,您需要创建一个新的 DocumentVersion对象。 您的DocumentVersion构造函数将采用FileVersion所需的参数,然后通过base()调用FileVersion构造函数。

请注意,如果您有一个现有的FileVersion对象,则可能需要一个对象来包装它,而不是从中派生一个对象。 例如,您的DocumentVersion不会派生自FileVersion ,而是包含对FileVersion的私有引用,以及根据需要的其他数据。 在这种情况下,这可能更合适。

例如(按OO术语,这是组成

public class DocumentVersion {
   private FileVersion fv;
   private String url;
   public DocumentVersion(FileVersion fv, String url) {
      this.fv = fv;
      this.url = url;
   }
}

有关合成的更多信息,请参见此处

您不能将FileVersionDocumentVersion因为您的fileversion变量包含FileVersion,而不是DocumentVersion。 继承是指:

  • 每个DocumentVersion都是一个FileVersion,但是
  • 并非每个FileVersion都是DocumentVersion!

如果对象是作为FileVersion创建的,则只是FileVersion。 期。 如果它是作为DocumentVersion创建的,则可以在使用FileVersion的任何地方使用它(请参阅上面的规则1), 并且可以使用它的DocumentVersion功能。

因此,在创建 FileVersion对象时,您需要创建一个DocumentVersion代替(如果您可以控制代码的这一部分),则强制转换将起作用。 这些DocumentVersions可以与FileVersions存储在同一列表中,因为每个DocumentVersion也是FileVersion。


编辑:由于上述两个规则对于理解OO原理至关重要,因此让我用一个示例进行说明:DocumentVersion = dog和FileVersion = animal。 那么上述规则将是:(1)每只狗都是动物,但(2)并非每只动物都是狗。 因此,您可以创建动物列表,在其中存储所有种类的动物(狗,猫,只是“动物”的东西,...),但是您不能将动物类型的变量强制转换为狗,除非在已经创建为狗(或作为狮子狗(类狮子狗:犬),它由规则 (1))。

用面向对象的术语:如果将狗存储在动物类型的变量中,则对象的静态类型为“动物”, 动态类型为“狗”。 如果元素的动态类型是T或其子类型,则只能将其转换为T类型。

您不能让父亲( FileVersion )扮演儿子( DocumentVersion )的角色。
反之亦然=>您可以让儿子当父亲。

(FileVersion)documentVersion //有效
(DocumentVersion)fileVersion //无效(因为fileVersion无法知道派生类型具有的内容)

这就是OOP的基础知识。

DocumentVersion dv = null;

if (fileversion is DocumentVersion)
{
    dv = fileversion as DocumentVersion;
}

(正如大多数答案所言,您无法回退FileVersion不知道什么是DocumentVersion )。

解决该问题的一种方法是在DocumentVersion的构造函数中复制字段

public partial class DocumentVersion : FileVersion
{
    public DocumentVersion() : base() { }

    public DocumentVersion(FileVersion version) : this()
    {
        this.id = version.id;
        // etc.
    }

    public string Link { get;set; }
}

或在DocumentVersion上创建一个静态方法,该方法从您提供的FileVersion返回一个DocumentVersion ,例如:

public static void New(FileVersion version)
{
    this.id = version.id;
    // etc.
}

提到的另一种技术是合成。 您将FileVersion作为属性存储在DocumentVersion

public class DocumentVersion
{
    public FileVersion FileVersion { get;set; }
    public string Link { get;set; }
}

由于您不能将FileVersion转换为DocumentVersion而您所需要做的就是添加获取URL的方法,因此您可以创建采用FileVersion扩展方法

public static string GetLink(this FileVersion fileVersion) {
  return "/files/"+fileVersion.id.ToString()+"/"+fileVersion.FileVersion.Last().Filename
}

注意:仅当使用C#3.0时,此方法才有效。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM