49

In a recent question on Stack Overflow, I asked how I might parse through a file name to extra meta info about a file.

After I worked through that problem, I decided that I might want to create new type of object to hold the meta data and the original file. I thought I might do something like this:

class BackupFileInfo : FileInfo, IEquatable<BackupFileInfo>
{
    //Properties and Methods here
}

The idea would be that I would retain the original FileInfo object while adding meta information in the properties of the object that implements FileInfo, such as IsMainBackup.

However, FileInfo is sealed, which means other classes cannot inherit from it.

Instead, I ended up with the following:

class BackupFileInfo : IEquatable<BackupFileInfo>
{
    public bool IsMainBackup { get; set; }
    public int ImageNumber { get; set; }
    public int IncrementNumber { get; set; }
    public FileInfo FileInfo { get; set; }

    //public BackupFileInfo() //constructor here

    public bool Equals(BackupFileInfo other)
    {
        return (this.FileInfo.Name == other.FileInfo.Name
             && this.FileInfo.Length == other.FileInfo.Length);
    }

}

I'm not terribly excited about this solution because instead of being able to use BackupFileInfo.Length, I'm going to have to use BackupFileInfo.FileInfo.Length. Perhaps this is the best practice already, but something doesn't feel right.

Is there a better way to deal with this problem?

Community
  • 1
  • 1
Ben McCormack
  • 32,086
  • 48
  • 148
  • 223

6 Answers6

36

This is one of the classic composition instead of inheritance examples and you went in the right direction.

To solve your property problem just create a property called Length that delegates to the encapsulated FileInfo object.

Restore the Data Dumps
  • 38,967
  • 12
  • 96
  • 122
15

You could add an implicit operator to your class.

Eg:

class BackupFileInfo .... {
  /* your exiting code */

  public static implicit operator FileInfo( BackupFileInfo self ){
     return self.FileInfo;
  }
}

You could then treat your BackupFileInfo object like a FileInfo object like so

BackupFileInfo bf = new BackupFileInfo();
...
int mylen = ((FileInfo)bf).Length;
Community
  • 1
  • 1
IanNorton
  • 7,145
  • 2
  • 25
  • 28
  • 1
    so I would have to cast the `BackupFileInfo` as a `FileInfo` in order to access the properties and methods of `FileInfo`? If that's the case, I think I'd rather just use `BackupFileInfo.FileInfo`. – Ben McCormack Jan 07 '10 at 21:37
  • 2
    doesn't solve the problem but +1 because it's really interesting! – K-Dawg Jun 01 '17 at 13:58
  • link to implicit doc appears dead – Jerther Jan 31 '18 at 20:29
  • @Jerther, the current documentation for the implicit operator can be found here: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/implicit. I have a pending edit to update the link in the answer. – Adrian Sanguineti Jun 21 '18 at 00:34
  • Did you mean `public static implicit` **`operator`** `FileInfo(BackupFileInfo self) { ...}` ? – Matt Oct 07 '19 at 12:07
11

You could just expose the properties on FileInfo you care about. Something like this:

public long Length { get { return FileInfo.Length; } }

This obviously becomes less practical if you want to delegate a lot of properties to FileInfo.

Sean Devlin
  • 1,662
  • 12
  • 17
6

Pass-thru?

class BackupFileInfo : IEquatable<BackupFileInfo>
{
    public long Length {get {return FileInfo.Length;}}
    //.... [snip]
}

Also, a prop called FileInfo is asking for trouble... it may need disambiguation against the FileInfo class in a few places.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Good point about the `FileInfo` naming convention. I was trying to avoid annoying myself with names like `MyFileInfo`, `ThisFileInfo`, `SuperFileInfo`. – Ben McCormack Jan 07 '10 at 21:36
  • 3
    Actually, giving a property the same name than its type (when it makes sense) is recommended over adding such prefixes and common enough in the BCL (SolidBrush.Color, for example). See Naming Guidelines at http://msdn.microsoft.com/en-us/library/fzcth91k.aspx . – Trillian Jan 07 '10 at 22:31
2

You can easily wrap the file info properties in your own properties if you like.

public long Length
{
    get
    {
       return this.FileInfo.Length;
    }
}
Paul Creasey
  • 28,321
  • 10
  • 54
  • 90
2

This doesn't really solve your larger problem, but of course you can just make the properties you want to use act as proxies to the real properties underneath. E.g.

public long Length
{
    get {return FileInfo.Length;}
}

(With approriate null-checking of course.)

Gaz
  • 4,064
  • 3
  • 32
  • 34