Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top