简体   繁体   中英

Generic Covariance and Casting to SuperType

I have an OO problem that I think can be tied back to Generic Covariance. I am trying to build a modular system for importing different types of records... Module contains the common methods, and the SalesModule contains the functions that handle specific logic...

public interface IImportable { ... void BuildSqlDataRecord(); ...  }
public class Sales : IImportable { ... }
public interface IModule<out T> where T : IImportable
{
    void Import(IEnumerable<T> list);  // Error Occurs here...
    IEnumerable<T> LoadFromTextFile(TextReader sr);
}
public abstract class Module<T> : IModule<T> where T : IImportable
{ 
    public void Import(IEnumerable<T> list) { ... T.BuildSqlDataRecord(); ... } 
    public IEnumerable<T> LoadFromTextFile(TextReader sr) { ... }
}
public class SalesModule : Module<Sales>
{
    public override void BuildSqlDataRecord() { ... }; 
}

and in the other function:

//Module<IImportable> module = null;
IModule<IImportable> module = null;
if(file.Name == "SALES")
    module = new SalesModule();
else
    module = new InventoryModule();

var list = module.LoadFromTextFile(sr);
module.Import(list);  

How do I declare the module such that I can call the overridden methods?

public interface IModule<out T> where T : IImportable
{
    void Import(IEnumerable<T> list);  // Error Occurs here...
    IEnumerable<T> LoadFromTextFile(TextReader sr);
}

The error is correct. We chose "out" as the keyword that indicates covariance as a reminder to you that T can only appear in "output" positions. In the line you highlight, T appears as an input.

T must not be an input because... well, suppose it was allowed and see what bad things happen:

IModule<Giraffe> gm = GetMeAModuleOfGiraffes();
IModule<Animal> am = gm; // Legal because of covariance.
IEnumerable<Tiger> tigers = GetMeASequenceOfTigers();
IEnumerable<Animal> animals = tigers; // Legal because of covariance.
am.Import(animals); // Uh oh.

You just imported a list of tigers into a module that only knows how to handle giraffes.

To prevent this, the step that has to be made illegal is the very first one. The type declaration is illegal with "out".

How do I declare the module such that I can call the overridden methods?

You have to declare the interface so that it obeys the rules of covariance. How you do that is up to you, but start by not putting any "out" parameters into "input" positions.

You'll need to use an interface for your module:

public interface IModule<out T> where T : IImportable 
{
  void DoStuff();
  void DoOtherStuff();
}

Then you'll be able to declare your module like so:

IModule<IImportable> = null;

See here for the MSDN documentation for the out generic mdoifier.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM