将 C# 方法转换为泛型方法

Converting c# methods to a generic method

如何将这两个 ConvertDtoListToAddressesConvertDtoListToDocuments C# 方法转换为 generic?我试过传递两个通用类型变量,但是当我在循环中进入 'Add' 时,我遇到了各种错误。从 DTO 到其各自 DBO 的转换是在 DBO 的构造函数中完成的,我认为这是问题的一部分。

private void ConvertDtoToPerson(PersonDTO dto)
{
    Id = dto.Id;
    Fname = dto.FirstName;
    Mname = dto.MiddleName;
    Lname = dto.LastName;
    Suffix = dto.Suffix;
    Maiden = dto.MaidenName;
    Addresses = ConvertDtoListToAddresses(dto.AddressesDto); // want to convert to generic
    Documents = ConvertDtoListToDocuments(dto.DocumentsDto); // want to convert to generic
}

private static ICollection<Address>? ConvertDtoListToAddresses(ICollection<AddressDTO>? addressesDto)
{
    if (addressesDto is not null && addressesDto.Any())
    {
        ICollection<Address> addys = new List<Address>();

        foreach (AddressDTO dto in addressesDto)
        {
            // Converts from dto in constructor
            addys.Add(new Address(dto));
        }

        return addys;
    }

    return null;
}

private static ICollection<Document>? ConvertDtoListToDocuments(ICollection<DocumentDTO>? documentsDto)
{
    if (documentsDto is not null && documentsDto.Any())
    {
        ICollection<Document> docs = new List<Document>();

        foreach (DocumentDTO dto in documentsDto)
        {
            // Converts from dto in constructor
            docs.Add(new Document(dto));
        }

        return docs;
    }

    return null;
}

这是我尝试过的:

Addresses = ConvertDtoListToType<Address, AddressDTO>(dto.AddressesDto);
private static ICollection<T>? ConvertDtoListToType<T, D>(ICollection<D>? dtoCollection)
{
    if (dtoCollection is not null && dtoCollection.Any())
    {
        ICollection<T> tList = new List<T>();

        foreach (D dto in dtoCollection)
        {
            tList.Add(new T(dto));  // <-- This is where I'm having trouble
        }

        return tList;
    }

    return null;
}

使用 Func<D, T> factory 参数可以解决这个问题。

private static ICollection<T>? ConvertDtoListToType<T, D>(ICollection<D>? dtoCollection, Func<D, T> factory)
{
    if (dtoCollection is not null && dtoCollection.Any())
    {
        ICollection<T> tList = new List<T>();
        foreach (D dto in dtoCollection)
        {
            tList.Add(factory(dto));
        }
        return tList;
    }
    return null;
}

请记住,这 几乎 语义等同于此:

private static ICollection<T>? ConvertDtoListToType<T, D>(ICollection<D>? dtoCollection, Func<D, T> factory)
    => dtoCollection?.Select(d => factory(d))?.ToList();

我质疑一个空 dtoCollection 应该 return 一个 null 最终集合的想法。这可能是一个更好的实现。

因此,话虽如此,您的原始方法提供的功能优势非常小。这是为了代码而编写的代码。一个简单的 Select/ToList 对让您的代码简单。

在任何情况下,您都可以提供 AddressDocument 的静态方法来提供您需要的 Func<D, T>

public class Address
{
    AddressDTO dto;

    public static Address CreateFromDto(AddressDTO dto)
        => new Address(dto);

    public Address(AddressDTO dto)
    {
        this.dto = dto;
    }
}

现在,调用它是这样的:

var addresses = ConvertDtoListToType(addressDtos, Address.CreateFromDto);

或:

var addresses = addressDtos?.Select(Address.CreateFromDto)?.ToList();

您需要的是能够对类型 T 提供约束,以表明它具有采用类型 D 参数的构造函数。像这样:

private static ICollection<T>? ConvertDtoListToType<T, D>(
  ICollection<D>? dtoCollection) where T : new(D) 
{}

但这在C#中是不存在的。解决方法是提供一个工厂方法来创建给定类型 D 的类型 T。即类似于:

private static ICollection<T>? ConvertDtoListToType<T, D>(
  ICollection<D>? dtoCollection, Func<D, T> factory)
{
    // Use factory(dto), instead of new T(dto)
}

但是正如@Zee 所说,您应该看看 Automapper,它可以在集合类型之间进行转换。