Cast concrete class to generic base interface

吃可爱长大的小学妹 提交于 2019-12-10 11:09:47

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!