重构以获得正确的继承/接口/协方差

本文关键字:继承 接口 方差 重构 | 更新日期: 2023-09-27 18:05:20

编辑:我已经添加了c#的相应功能,以吸引更广泛的受众-希望这是可以的

VS2008 - .Net 3.5(因此我没有得到协方差/逆变支持,据我所知?)

似乎这可能需要协方差/逆变性,因此需要。net 4,所以为了防止这个问题不可能,请随意回答。net 4,尽管如此,如果它可用,我更喜欢一个简单的重构。

这应该很简单,但由于某种原因,我的大脑今天早上就是无法应对(任何?)挑战。

我有2个应用程序(A &B).应用程序A的细节希望不重要,所以以下是WRT AppB,它有3个项目,所有类库:

  1. 将我的域实体暴露给AppB的其余部分,并且也暴露给AppA
  2. 只向AppB公开我的数据模型(使用L2S, 正常上下文和实体)
  3. 向AppA公开功能,使用域实体作为参数/返回类型

我在3个不同的项目中有以下接口:

Project 1 (Domain Entities)

VB:

Public Interface IAppB_Project1_Contract(Of TKey)
     ReadOnly Property UniqueReference As TKey
End Interface
c#

public interface IAppB_Project1_Contract<TKey>
{
    TKey UniqueReference { get; }
}

项目2(数据模型)

VB:

Public Interface IAppB_Project2_Contract(Of TKey)
     Inherits IAppB_Project1_Contract(Of TKey)
End Interface
c#:

public interface IAppB_Project2_Contract<TKey> : IAppB_Project1_Contract<TKey>
{
}

项目3(功能)

VB:

Public Interface IAppB_Project3_Contract
     Function Create(Of T As {Class, IAppB_Project1_Contract(Of TKey)}, TKey)(ByVal entity As T) As TKey
End Interface
c#:

public interface IAppB_Project3_Contract
{
    TKey Create<T, TKey>(T entity) where T : class, IAppB_Project1_Contract<TKey>;
}

这个想法是功能契约(在项目3中)将只使用域实体(在项目1中)作为参数/返回,因为只有项目1和项目3暴露给应用程序A,项目2不是。

我的L2S实体被扩展以实现Project 2接口。项目2的合同中实际上有几个额外的方法,但希望不是相关的。

在我真正键入它之前,出于某种原因,我在脑海中有一个想法,我将使用项目3的合同的以下实现:

VB:

Public Class Project3_Implementation
    Implements IAppB_Project3_Contract
    Public Function Create(Of T As {Class, IApp_Project2_Contract(Of TKey)}, TKey)(ByVal entity As T) As TKey Implements IAppB_Project3_Contract.Create
        ' notice the very subtle change to *Project TWO's* contract in the generics' constraint
    End Function
End Class
c#:

public class Project3_Implementation : IAppB_Project3_Contract
{
    public TKey Create<T, TKey>(T entity) where T : class, IApp_Project2_Contract<TKey>
    {
        // notice the very subtle change to *Project TWO's* contract in the generics' constraint
    }
}

这在我的脑海里工作了一段时间,因为项目2的合同继承了项目1的合同,但这当然不是这样,因为我把缩小了的约束,因此不能实现相应的项目3接口。

问题是,我该如何去实现我所追求的:

  • 项目2应该对应用A保持不可见,但项目1和3是公开的,并且应该描述可用的功能和应用A可以/必须使用的实体,以便调用应用B
  • 理想情况下,项目3合同的实施将参数限制为隐藏项目2中声明的实体。

我有一种感觉,我在要求不可能的事情,但我希望有人能跳出框框,提出一些我可以改变的事情来实现,或者接近实现我的目标?

提前感谢!!

编辑:

我知道这个问题不会很清楚,因为我在问题中描述的只是如何做错误的事情

这里有更多关于项目3的合约实现的细节,希望能让事情更清楚(记住项目2的合约只由自动生成的Linq实体实现):

VB:

Public Class MyImplementation
    Inherits System.Data.Linq.DataContext
    Implements IAppB_Project3_Contract
    Public Function Create(Of T As {Class, IApp_Project2_Contract(Of TKey)}, TKey)(ByVal entity As T) As TKey Implements IAppB_Project3_Contract.Create
        Me.GetTable(Of T).InsertOnSubmit(entity)
        Return entity.UniqueReference        ' the entity will implement the IApp_Project2_Contract by exposings it primary key - Return Me.MyPrimaryKeyField
    End Function
End Class
c#:

public class MyImplementation : System.Data.Linq.DataContext, IAppB_Project3_Contract
{
    public TKey Create<T, TKey>(T entity) where T : class, IApp_Project2_Contract<TKey>
    {
        this.GetTable<T>.InsertOnSubmit(entity);
        return entity.UniqueReference;
        // the entity will implement the IApp_Project2_Contract by exposings it primary key - Return Me.MyPrimaryKeyField
    }
}

重构以获得正确的继承/接口/协方差

如果你像这样声明你的接口会发生什么?这将需要。net 4.0+

Public Interface IAppB_Project1_Contract(Of Out TKey)
    ReadOnly Property UniqueReference As TKey 
End Interface
Public Interface IAppB_Project2_Contract(Of Out TKey)
    Inherits IAppB_Project1_Contract(Of TKey)
End Interface
Public Interface IAppB_Project3_Contract
    Function Create(Of T As {Class, IAppB_Project1_Contract(Of TKey)}, 
                    TKey)(ByVal entity As T) As TKey       
End Interface

这会使接口的继承者与父类型共变并使代码能够运行吗?