初学者:用 C# 扩展一个类,我做错了吗?

发布于 2024-08-10 21:07:54 字数 1152 浏览 7 评论 0原文

再说一遍免责声明总体上仍在学习 C# 和 OOP,所以我希望你能对我有耐心 :)

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

FileVersion 列表包含在 File 有它自己的唯一 ID。当您想要从 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;
}

现在我应该注意,看来我不需要在这里实现接口 - 但不要将此视为福音,这就是我在这里的原因。

但是,当我尝试将我的 FileVersion 转换为 DocumentVersion 时,如下所示:

DocumentVersion dv = ((DocumentVersion)fileversion);

我收到以下异常:

无法转换类型的对象 键入“Foo.CMS.FileVersion” 'CoA.DocumentVersion'。

我的直觉是,这是因为我试图在与原始类所在的不同命名空间中扩展一个类,但正如我所说,OOP 对我来说相对较新,所以我可能是错的。

预先感谢您的帮助。这个社区太有价值了!我只是希望一旦我更加熟练,我可以回馈一些:)。

Again disclaimer disclaimer still learning C# and OOP generally so I hope you'll be patient with me :)

I am currently working with a CMS that has a class called FileVersion which basically contains a list of properties pertaining to a file such as filename, filetype, size in bytes, id, date uploaded, is-latest-version, etc.

A list of FileVersions is contained within a File which has it's own unique ID. When you want to download a particular file from the CMS, the URL is built using something like the following:

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

Now for a particular control I'm working on (dealing specifically with files that are documents), it makes sense to be able to store the URL along with all the other FileVersion information for later use. So what I've decided to do is create my own class called DocumentVersion which extends FileVersion. This is what it looks like:

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

Now I should note, that it appears that I don't need to implement an interface here - but don't take that as gospel, that's why I'm here.

However when I try to cast my FileVersion as a DocumentVersion like so:

DocumentVersion dv = ((DocumentVersion)fileversion);

I get the following exception:

Unable to cast object of type
'Foo.CMS.FileVersion' to type
'CoA.DocumentVersion'.

My inkling is that it's because I'm trying to extend a class in a different namespace from where the original resides, but like I said, OOP is relatively new to me so I could be wrong.

Thanks in advance for your help. This community has been so valuable! I just hope once I'm more skilled up I can give some back :).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

人心善变 2024-08-17 21:07:54

你想沮丧吗?即采用现有的 FileVersion 并将其声明为 DocumentVersion

如果是这样,您就不能这样做,因为您所拥有的只不过是一个FileVersion

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

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

例如(在面向对象的术语中,这是组合

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

请参阅此处了解有关构图的更多信息。

Are you trying to downcast ? i.e. take an existing FileVersion and declare it to be a DocumentVersion ?

If so, you can't do that, since what you have is nothing more than a FileVersion.

Instead you need to create a new DocumentVersion object. Your DocumentVersion constructor will take the arguments required for a FileVersion and then call the FileVersion constructor via base().

Note that if you have an existing FileVersion object, you may want an object to wrap this, rather than have an object deriving from it. e.g. your DocumentVersion wouldn't derive from FileVersion, but contain a private reference to a FileVersion, plus additional data as required. That may be more appropriate in this scenario.

e.g. (in OO terms this is composition)

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

See here for more info on composition.

半枫 2024-08-17 21:07:54

您无法将 FileVersion 转换为 DocumentVersion,因为您的 fileversion 变量包含 FileVersion,而不是 DocumentVersion。 继承意味着以下内容:

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

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

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


编辑:由于上述两条规则对于理解 OO 原则非常重要,让我用一个例子来说明它们:DocumentVersion = dogs 和 FileVersion = Animal。那么上述规则将是:(1)每只狗都是动物,但(2)并非每只动物都是狗。因此,您可以创建一个动物列表,在其中存储各种动物(狗,猫,只是“动物”的东西,...),但是您不能将动物类型的变量强制转换为狗,除非什么在那里已被创建为狗(或贵宾犬(贵宾犬类:狗),根据规则(1),它是狗)。

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

You cannot cast your FileVersion to DocumentVersion because your fileversion variable contains a FileVersion, not a DocumentVersion. Inheritance means the following:

  • Every DocumentVersion is a FileVersion, but
  • Not every FileVersion is a DocumentVersion!

If the object was created as a FileVersion, it's just a FileVersion. Period. If it was created as a DocumentVersion, you can use it everywhere where you would use a FileVersion (see rule #1 above), and you can use the DocumentVersion features of it.

So, when creating the FileVersion object, you need to create a DocumentVersion instead (if you have control over that part of the code), then the cast will work. Those DocumentVersions could be stored in the same list as the FileVersions, since every DocumentVersion is also a FileVersion.


EDIT: Since the above two rules are so vital to understanding the OO principle, let me illustrate them with an example: DocumentVersion = dog and FileVersion = animal. Then the above rules would be: (1) Every dog is an animal, but (2) not every animal is a dog. So, you can create a list of animals, store all kinds of animals in there (dogs, cats, things that are just "animal", ...), but you cannot cast a variable of type animal to a dog, unless what is in there has been created as a dog (or as a poodle (class poodle : dog), which is a dog by rule (1)).

In OO terms: If you store a dog in a variable of type animal, then the static type of the object is "animal", and the dynamic type is "dog". You can only cast an element to some type T if its dynamic type is T or a subtype thereof.

听风念你 2024-08-17 21:07:54

您无法让父亲 (FileVersion) 表现得像儿子 (DocumentVersion)。
只有反之亦然=>你可以让儿子当父亲。

(FileVersion)documentVersion //有效
(DocumentVersion)fileVersion //无效(因为 fileVersion 无法了解派生类型拥有的内容)

这是 OOP 基础知识。

You can't make father (FileVersion) to act like son (DocumentVersion).
Only vica versa => you can make son as father.

(FileVersion)documentVersion //valid
(DocumentVersion)fileVersion //invalid (because fileVersion can't know about stuff that derived type has)

That's OOP basics.

听风吹 2024-08-17 21:07:54
DocumentVersion dv = null;

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

if (fileversion is DocumentVersion)
{
    dv = fileversion as DocumentVersion;
}
往日情怀 2024-08-17 21:07:54

(正如大多数答案所说,您无法进行备份 - 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; }
}

(As most answers have said, you can't cast back up - FileVersion has no idea what a DocumentVersion is).

One way to get around it is to copy the fields in the constructor of DocumentVersion

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

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

    public string Link { get;set; }
}

Or create a static method on DocumentVersion that returns a DocumentVersion from the FileVersion you provide it, e.g:

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

Another technique mentioned, is composition. You store the FileVersion as a property in DocumentVersion

public class DocumentVersion
{
    public FileVersion FileVersion { get;set; }
    public string Link { get;set; }
}
紫罗兰の梦幻 2024-08-17 21:07:54

由于您无法将 FileVersion 转换为 DocumentVersion 并且您需要做的就是添加一个方法来获取 URL,因此您可以创建一个 采用 FileVersion 的扩展方法

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

注意:这仅在您使用 C# 3.0 时有效。

Since you cannot convert a FileVersion to a DocumentVersion and all you need to do is add a method to get the URL, you could create an extension method that takes a FileVersion:

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

Note : this only works if you are using C# 3.0.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文