在具有约束的另一个泛型接口中使用接口无法编译

本文关键字:接口 编译 泛型接口 约束 另一个 | 更新日期: 2023-09-27 18:03:24

我已经为我的服务层构建了一个通用的数据转换器,现在我正在尝试构建接口,以便我可以使用依赖注入(Autofac)来进行绑定。然而,我不能得到注入编译所需的最终接口。我已经建立了一个简单的例子,我在下面列出:

public interface IMyData
{
    int I { get; set; }
}
public class MyData : IMyData
{
    public int I { get; set; }
}
public interface IMyDto
{
    int J { get; set; }
}
public class MyDto : IMyDto
{
    public int J { get; set; }
}
public class MyService<TData, TDto> : IMyService<TData, TDto>
    where TData : class, new()
    where TDto : GenericDto<TData, TDto>, new()
{
    public TDto DoSomething(TData data)
    {
        return new TDto();
    }
}
public interface IMyService<in TData, out TDto>
    where TData : class, new()
    where TDto : GenericDto<TData, TDto>, new()
{
    TDto DoSomething(TData data);
}
public class TryToUse
{
    private MyService<MyData, MyDto> actualServiceActualClasses;         //OK
    private IMyService<MyData, MyDto> interfaceServiceActualClasses;     //OK
    //fails with two messages, both the same for IMyData and IMyDto
    //'TryGenericInterfaces.IMyDto' must be a non-abstract type with a public
    //parameterless constructor in order to use it as parameter 'TDto' in the 
    //generic type or method 'TryGenericInterfaces.IMyService<TData,TDto>'
    private IMyService<IMyData, IMyDto> interfaceServiceInterfaceClasses; //fails
}

您将看到我在违规声明上方嵌入了编译时错误。不用说,这是我需要依赖注入工作的最后声明(也因为这是我想要的声明方式)。

这是接口的限制还是我只是错过了什么?

感谢@D Stanley和其他人指出我的误解。我想你可以看到我正在尝试做什么,这是建立一个通用的数据到DTO和DTO到数据转换器。在AutoMapper的帮助下,代码工作得很好。(我已经更新了代码,以包含每个DTO继承的GenericDto)。

这个问题没有经过深思熟虑,我很抱歉。我已经提供了一个与你们一致的答案,也解释了我最终试图实现的目标(现在实际上正在工作)。

在具有约束的另一个泛型接口中使用接口无法编译

错误似乎很明显-您已经指定TDataTDto必须是具有无参数构造函数的类,但是您试图使用接口(既不是类也没有构造函数)作为泛型参数。除非你能移除class, new()限制,否则我看不到这个

这个可以吗?

public interface IMyService<in TData, out TDto>
    where TData : IMyData
    where TDto : IMyDto
{
    TDto DoSomething(TData data);
}

public class MyService<TData, TDto> : IMyService<TData, TDto>
    where TData : class, IMyData, new()
    where TDto : class, IMyDto, new()
{
    public TDto DoSomething(TData data)
    {
        return new TDto();
    }
}

对不起,我犯了一个愚蠢的错误。我不知道我昨天抽了什么烟,但是睡了一个好觉之后,我现在清醒了。

@rhughes指出(见下面的注释)是新的()约束阻止了泛型定义接受接口,这是一个很好的建议。我确实尝试过,但实体框架(EF)不会与接口(已知的设计点)一起工作,所以我在我的通用定义中保留了真正的类,即

private IMyService<MyData, MyDto>

为了在EF中使用我的通用服务,我将不得不放松只在层之间传递接口的设计目标。然而,总的来说,获得泛型服务和类通常只是数据的事实意味着,在这些情况下,我可以放松只在层之间传递接口的规则。

还有一些人问我为什么在我举的例子中需要一个泛型。我应该解释一下,因为这是一个接口问题,我删除了一些代码,使问题更简单(代码相当长)。实际上,服务的签名包括一个泛型类,作为TDto部分的约束。完整的定义是:

public class MyService<TData, TDto> : IMyService<TData, TDto>
    where TData : class, new()
    where TDto : GenericDto<TData, TDto>, new()

GenericDto是一个抽象类,它包含许多方法,用于转换TData->TDto和TDto->TData的数据。这些默认方法使用AutoMapper,下面是构建列表查询的示例,该查询接受EF类并将其转换为可查询的TDto:

internal virtual IQueryable<TDto> BuildListQueryUntracked(TemplateWebAppDb context)
{
    Mapper.CreateMap<TData, TDto>();
    return context.Set<TData>().AsNoTracking().Project().To<TDto>();
}

当转换对AutoMapper来说太复杂时,这些默认的转换可以被实际的Dto类覆盖。然而,我应该说我发现AutoMapper非常好,特别是现在它可以投影到IQueryable。

感谢大家的帮助,很抱歉我的大脑冻结了。