将具体类转换为通用基接口

时间:2009-11-22 06:46:57

标签: c# interface generics casting base

以下是我面临的情景:

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 { }

现在,当我尝试进行以下演员时,它不会编译:

UserDataAccessLayer udal = new UserDataAccessLayer();
            ITableDataAccessLayer<TableRecord> itdal = (ITableDataAccessLayer<TableRecord>)udal;

然而,当我执行以下转换时,它编译时没有运行时错误:

UserDataAccessLayer udal = new UserDataAccessLayer();
            ITableDataAccessLayer<UserRecord> itdal = (ITableDataAccessLayer<UserRecord>)udal;

我真的需要使用基础ITableDataAccessLayer<TableRecord>接口,因为我不知道具体的类型。

希望这是一个描述性的,有用的回答我的问题。

3 个答案:

答案 0 :(得分:5)

.NET 4.0支持您尝试执行的操作,但不支持3.5。它被称为generic covariance。在此期间您可以做的是创建一个名为ITableDataAccessLayer的非泛型接口(使用类型Object,无论您使用何时使用T)并提供显式接口实现。这是.NET中有多少泛型类型处理它。

答案 1 :(得分:4)

确实,你想要协方差。情侣点。

首先,要明白为什么有时这必须是非法的。以IList为例。假设你有一个IList<Giraffe>,一个长颈鹿列表。你能把它转换成动物名单吗?不,不安全。是的,长颈鹿列表是动物列表,因为列表中的所有内容都是动物。但是名单是可变的;你可以将一只老虎放入动物名单中,但如果它真的是长颈鹿的名单,那么这必须失败。由于这不安全,我们不会在C#4中使IList协变。

其次,如果您对此主题感兴趣,您可能需要阅读我关于该功能如何设计以保持类型安全性的一系列博客文章。

http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx

第三,仅供参考我将在未来几周内在我的博客上发布一个界面可以安全协变或逆变的时候发布我们用来计算的确切规则。

答案 2 :(得分:0)

这会编译吗?

UserDataAccessLayer udal = new UserDataAccessLayer(); 
ITableDataAccessLayer<TTableRecord> itdal = (ITableDataAccessLayer<TTableRecord>)udal;

甚至只是

ITableDataAccessLayer<TTableRecord> itdal = new UserDataAccessLayer(); 

因为它是一个通用接口,它可能需要知道它是什么类型的?

知道错误消息也会有所帮助。这通常可以说明这个问题。