.NET 4.0 通用不变式、协变式、逆变式

问题描述 投票:0回答:2

这是我面临的场景:

public abstract class Record { } 

public abstract class TableRecord : Record { } 

public abstract class LookupTableRecord : TableRecord { } 

public sealed class UserRecord : LookupTableRecord { } 

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

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

现在,当我尝试将 UserDataAccessLayer 转换为其通用基类型

ITableDataAccessLayer<TableRecord>
时,编译器抱怨它无法隐式转换类型。

当我尝试在泛型参数的接口声明中使用

in
out
关键字时,编译器会抱怨 无效方差:类型参数必须始终有效。

我有以下抽象类:

public abstract class FileProcessor : IDisposable
{
    protected abstract ITableDataAccessLayer<TableRecord> CreateTableDataAccessLayer();
}

具体实现示例如下:

public class UserFileProcessor : FileProcessor
{
            protected override ITableDataAccessLayer<TableRecord> CreateTableDataAccessLayer()
        {
            return new UserDataAccessLayer();
        }
}

返回新的UserDataAccessLayer();这是编译器抱怨的地方。

.net generics .net-4.0 covariance contravariance
2个回答
0
投票

协变和逆变的问题在于它对所涉及的类型施加了相当多的限制,因此它可能并不适用于所有情况。

我设法通过进行以下更改来编译您的代码:

public interface IDataAccessLayer<out TRecord>
    where TRecord : Record { }

public interface ITableDataAccessLayer<out TTableRecord> : IDataAccessLayer<TTableRecord>
    where TTableRecord : TableRecord { }

注:

  • 为 IDataAccessLayer 和 ITableDataAccessLayer 添加了输出

但是,这意味着您不限于仅在这些类型的输出位置中使用 TTableRecord,这意味着:

  • 只读属性的类型(不适用于可写属性)
  • 方法的返回类型
  • 方法的参数类型

您可以将其用于:

  • 可写属性
  • 方法的引用或非输出/引用参数

很可能,没有办法让同方差和逆变方差在这里为您提供帮助。


0
投票

据我所知,如果你想使用协方差,你需要为接口指定 out 关键字。

链接

© www.soinside.com 2019 - 2024. All rights reserved.