【问题标题】:Return List based on generic T基于泛型 T 的返回列表
【发布时间】:2020-02-17 12:18:07
【问题描述】:

我想将TEntity 的列表转换为TDto 的列表。

    private List<TDto> ConvertUEntityToDto<TDto, TEntity>(IEnumerable<TEntity> entities)
    {
        if (entities is IEnumerable<Entity1>)
        {
            var result = new List<EntityDto1>
            foreach (var entity in entities)
            {
                result.Add(_mapper.Map<EntityDto1>(entity ));
            }

            return result;
        }

        else if (entities is IEnumerable<Entity2>)
        {
            var result = new List<EntityDto2>
            foreach (var entity in entities)
            {
                result.Add(_mapper.Map<EntityDto2>(entity));
            }

            return result;
        }

        return null;
    }

从上面的代码我得到一个错误:

错误 CS0029 无法将类型“System.Collections.Generic.List”隐式转换为“System.Collections.Generic.List

如何从 C# 中的泛型方法动态返回 T 列表?

【问题讨论】:

  • EntityDto2TDto是什么关系?您声明返回类型为TDto,但初始化EntityDto2 列表。将列表更改为List&lt;TDto&gt;
  • Tdto 是类但我写where TDto : classstill 相同的错误
  • 从技术上讲,return result as List&lt;TDto&gt; 可能会解决您的问题。但是,正如@GiladGreen 所指出的,有更好的方法来实现这种泛型映射,它通常包括一些泛型约束的使用来表示所涉及的类型之间的关系。
  • 制作这个通用函数有什么好处,好像你已经在映射器实现中拥有了逻辑?并且可以只使用entities.Select(e => _mapper.Map(e)); ?
  • 问题是您正在用泛型方法编写特定于类型的代码。您要么需要通过使用TDto 来使您的代码在通用内部,要么您必须要求编译器相信您的类型是兼容的,通过执行x as TDto(TDto)(object)x,具体取决于类型参与。

标签: c# generics


【解决方案1】:

泛型的意义在于使用它们! if-else 应该在您的通用函数之前(另请参阅下面的编辑)。

if (entities is IEnumerable<Entity1>)
    ConvertUEntityToDto<TDto1, Entity1>(entities);
else if (entities is IEnumerable<Entity2>)
    ConvertUEntityToDto<TDto2, Entity2>(entities);
else ; //do nothing

ConvertUEntityToDto 内部,它应该使用 T (TDto),如下所示:

private List<TDto> ConvertUEntityToDto<TDto, TEntity>(IEnumerable<TEntity> entities)
{
    var result = new List<TDto>
    foreach (var entity in entities)
    {
        result.Add(_mapper.Map<TDto>(entity));
    }
    return result;
}

错误是因为返回类型与您的函数的签名不匹配。

但我想提一下

您可以只传入一个列表,使用 foreach 对其进行迭代,如果列表中的元素是 T 类型,则添加到您返回的新 List&lt;T&gt;

另外,你应该有 constraints 代表 T。

编辑:

我上面提到的,要返回列表的所有元素,只匹配类型 TDto (并摆脱前面的 if-else 块),我们可以使用以下 sn-p (通过引用 System.Linq在项目中)(感谢@Janne Matikainen 提及):

private List<TDto> ConvertUEntityToDto<TDto, TEntity, Tmixed>(IEnumerable<Tmixed> entities)
{
    return entities.Where(e => e is TEntity).Select(e => _mapper.Map<TDto>(e));
}

相当于:

private List<TDto> ConvertUEntityToDto<TDto, TEntity, Tmixed>(IEnumerable<Tmixed> entities)
    => entities.Where(e => e is TEntity).Select(e => _mapper.Map<TDto>(e));

【讨论】:

  • 很好,但是你在转换方法Tdto2 中没有提及,你能解释一下Tdto2Tdto 之间的关系吗?
  • 这是您的代码的复制粘贴问题。现在看。 :) 如果您使用 T 和 U(或任何字母)会更容易。
  • 您也可以将方法设为“返回实体.Select(e => _mapper.Map(e));”即取消泛型方法的开始。基本上把它作为扩展方法是最有益的
  • @JanneMatikainen 扩展方法思想可能不适用于这里!因为_mapper(全局对象)会变成静态(或至少是引用类型参数),这是非常非线程安全的!此外,entities 是一个引用类型:它本身会使函数成为非线程安全的!但感谢 Linq 的想法。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-30
  • 1970-01-01
  • 1970-01-01
  • 2011-02-16
  • 2018-09-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多