Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Downcasting to generic type

Tags:

c#

I have the following classes:

public interface IFile { }

public class File : IFile { }

public class FTPFile : File { }

public interface IFileManager<T> where T : IFile
{
    void SaveFile(T file);
}

internal class FTPFileManager : IFileManager<FTPFile>
{
    public void SaveFile(FTPFile file) { }
}

I have multiple file types and managers defined in my project but I tried to keep it simple. In my factory class, I have a method like the following where it can't cast FTPFileManager to IFileManager<IFile> but interestingly it can cast FTPFileManager to IFileManager<FTPFile>. In both cases there is no compile error but in runtime it throws error.

public class FileManagerFactory
{
    public static IFileManager<IFile> GetFileManager(IFile file)
    {
        if (file is FTPFile)
            return (IFileManager<IFile>)new FTPFileManager(); //No compile error but in runtime it throws casting error
    }
}
like image 283
sotn Avatar asked Aug 28 '26 13:08

sotn


1 Answers

You would be able to cast FTPFileManager to IFileManager<IFile> if IFileManager were covariant, i.e. declared as:

public interface IFileManager<out T> where T : IFile

However, this won't compile because IFileManager has T as an input parameter to one of its methods. For an interface to be covariant in T, it must have T only as a type of return parameters.

This makes sense in your situation, because FTPFileManager needs to be given an instance of FTPFile. If you could write:

var ftpManager = new FtpFileManager();
IFileManager<IFile> fileManager = ftpManager;
fileManager.SaveFile(new SomeOtherFileType());

Then the FTP file manager would be expecting an FTPFile but instead be passed something else. For that reason, the second line refuses to compile.


Note that this also highlights a risk downcasting (or, at least, downcasting without being very clear on why you're doing it). By writing:

return (IFileManager<IFile>)new FTPFileManager();

instead of

return new FTPFileManager();

you turned a compile-time error into a runtime one.

like image 153
Ben Aaronson Avatar answered Aug 30 '26 04:08

Ben Aaronson



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!