1

再次免责声明 免责声明通常仍在学习 C# 和 OOP 所以我希望你能对我有耐心:)

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

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

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

现在对于我正在处理的特定控件(专门处理作为文档的文件),能够将 URL 与所有其他FileVersion信息一起存储以供以后使用是有意义的。所以我决定做的是创建我自己的名为DocumentVersionwhich extends的类FileVersion。这是它的样子:

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

现在我应该注意,我似乎不需要在这里实现一个接口——但不要把它当作福音,这就是我在这里的原因。

但是,当我尝试像这样投射我FileVersionDocumentVersion

DocumentVersion dv = ((DocumentVersion)fileversion);

我得到以下异常:

无法将“Foo.CMS.FileVersion”类型的对象转换为“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 :).

4

6 回答 6

5

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.

于 2009-11-10T10:46:45.870 回答
4

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.

于 2009-11-10T10:49:59.043 回答
1

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.

于 2009-11-10T10:44:44.547 回答
1
DocumentVersion dv = null;

if (fileversion is DocumentVersion)
{
    dv = fileversion as DocumentVersion;
}
于 2009-11-10T10:47:22.373 回答
1

(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; }
}
于 2009-11-10T10:52:07.137 回答
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.

于 2009-11-10T10:56:40.033 回答