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

发布于 2024-08-31 01:15:38 字数 2059 浏览 5 评论 0原文

这是我面临的场景:

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 时,编译器抱怨它无法隐式转换类型。

当我尝试在泛型参数的接口声明中使用 inout 关键字时,编译器会抱怨无效方差:类型参数必须始终有效

我有以下抽象类:

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

以及示例具体实现如下:

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

return new UserDataAccessLayer();这是编译器抱怨的地方。

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

Now when i try to cast UserDataAccessLayer to it's generic base type ITableDataAccessLayer<TableRecord>, the compiler complains that it cannot implicitly convert the type.

When i try and use the in or out keywords in the interface declaration for the generic parameters, the compiler complains about Invalid variance: The type parameter must be invariantly valid.

I have the following abstract class:

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

And a sample concrete implementation as follows:

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

return new UserDataAccessLayer(); is where the compiler is complaining.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

你不是我要的菜∠ 2024-09-07 01:15:38

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

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

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

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

注意:

  • 为 IDataAccessLayer 和 ITableDataAccessLayer 添加了 out,

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

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

您不能将其用于:

  • 可写属性
  • ref 或方法的非 out/ref 参数

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

The problem with co- and contra-variance is that it imposes quite a bit of restrictions on the types involved, so it might not be applicable in all cases.

I managed to get your code to compile by making the following changes:

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

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

Note:

  • out added for IDataAccessLayer and ITableDataAccessLayer

This, however, means you're not restricted to using TTableRecord only in output positions in those types, which means:

  • type for readonly properties (not for writeable properties)
  • return type for methods
  • out argument-types for methods

You can not use it for:

  • writeable properties
  • ref or non-out/ref parameters to methods

So likely, there is no way to make co- and contra-variance help you here.

九局 2024-09-07 01:15:38

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

链接

As far as I know you need to specify the out keyword for the interface if you want to use covariance.

Link

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文