For cases where you know the type at compile time, such as "please load this pdf, it's definitely going to be a pdf" - then I don't see any reason to look at generics at all. You're not saving yourself any time over just instantiating the object with the stream data, and letting it build itself.
// for example
class pdf : document {
public pdf(Stream stream)
{
// load the pdf data from the stream here
}
}
For cases where you don't know the object type, "load the file the user selected, it might be a pdf, it might be an excel file", you also don't want to be worrying about generics. Instead, you want a function that returns a base document type - as you don't know what type it is before loading (i.e. at compile time, you don't know - so you can't use generics):
document LoadFromStream(Stream stream)
{
var typeOfDocument = SomeMethodToFindTheFileTypeFromTheStream(stream);
switch(typeOfDocument)
{
case DocumentType.pdf:
return LoadPDFFromStream(stream); // returns pdf object
case DocumentType.excel:
return LoadExcelFromStream(stream); // returns an excel object
default:
throw new Exception("Document is not a supported type");
}
}
If you then need the specific object, you'll need to downcast it using information within the object (such as a document type enum) to figure out which type to cast it to.
There is no silver-bullet generic solution to this I'm afraid. If you know the file type at compile time, generics aren't saving you anything. If you don't - you need some conditional logic to determine what type it actually is (whether this is before or after loading, e.g. using the file extension to decide).
Generics won't save you time or make your life easier here at all.