问题
Here's the scenario i am faced with:
public abstract class Record { }
public abstract class TableRecord : Record { }
public abstract class LookupTableRecord : TableRecord { }
public sealed class UserRecord : LookupTableRecord { }
public abstract class DataAccessLayer<TRecord> : IDataAccessLayer<TRecord>
where TRecord : Record, new() { }
public abstract class TableDataAccessLayer<TTableRecord> : DataAccessLayer<TTableRecord>, ITableDataAccessLayer<TTableRecord>
where TTableRecord : TableRecord, new() { }
public abstract class LookupTableDataAccessLayer<TLookupTableRecord> : TableDataAccessLayer<TLookupTableRecord>, ILookupTableDataAccessLayer<TLookupTableRecord>
where TLookupTableRecord : LookupTableRecord, new() { }
public sealed class UserDataAccessLayer : LookupTableDataAccessLayer<UserRecord> { }
public interface IDataAccessLayer<TRecord>
where TRecord : Record { }
public interface ITableDataAccessLayer<TTableRecord> : IDataAccessLayer<TTableRecord>
where TTableRecord : TableRecord { }
public interface ILookupTableDataAccessLayer<TLookupTableRecord> : ITableDataAccessLayer<TLookupTableRecord>
where TLookupTableRecord : LookupTableRecord { }
Now, when i try to do the following cast, it does not compile:
UserDataAccessLayer udal = new UserDataAccessLayer();
ITableDataAccessLayer<TableRecord> itdal = (ITableDataAccessLayer<TableRecord>)udal;
However, when i do the following cast it compiles with no runtime errors:
UserDataAccessLayer udal = new UserDataAccessLayer();
ITableDataAccessLayer<UserRecord> itdal = (ITableDataAccessLayer<UserRecord>)udal;
I really need to work with the base ITableDataAccessLayer<TableRecord> interface, as i don't know the concrete type.
Hope this is descriptive and helpfull enough to answer my question.
回答1:
What you are trying to do is supported in .NET 4.0 but not 3.5. It's called generic covariance. What you can do instead in the meantime is create a non-generic interface called ITableDataAccessLayer (using type Object wherever you'd use T) and provide explicit interface implementation. This is how many generic types in .NET handle it.
回答2:
Indeed, you want covariance. Couple points.
First, understand why sometimes this has to be illegal. Take IList for example. Suppose you have an IList<Giraffe>, a list of giraffes. Can you convert that to a list of animals? No, not safely. Yes, a list of giraffes is a list of animals in the sense that everything in the list is an animal. But lists are mutable; you can stick a tiger into a list of animals, but if it is really a list of giraffes then this has to fail. Since that is not safe, we will not be making IList covariant in C# 4.
Second, if this topic interests you, you might want to read my long series of blog articles on how the feature is designed to maintain type safety.
http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx
Third, FYI I will be posting the exact rules we use to compute when an interface can be safely covariant or contravariant on my blog in the next couple of weeks.
回答3:
does this compile?
UserDataAccessLayer udal = new UserDataAccessLayer();
ITableDataAccessLayer<TTableRecord> itdal = (ITableDataAccessLayer<TTableRecord>)udal;
or even just
ITableDataAccessLayer<TTableRecord> itdal = new UserDataAccessLayer();
as it is a generic interface, it probably needs to know what type it is?
it would be helpful to know the error message too. that usually sheds light on the subject.
来源:https://stackoverflow.com/questions/1778030/cast-concrete-class-to-generic-base-interface