使用泛型编写类似的逻辑

时间:2017-07-25 14:47:54

标签: c# .net generics

我有以下方法确定我需要从数据库中删除哪些车辆。

private List<CarDTO> BuildCarsToDelete(IList<CarDTO> newCars, IList<CarDTO> existingCars)
{
    var missingCars = new List<CarDTO>();

    var cars = newCars.Select(c => c.CarId);
    var newCarIds = new HashSet<int>(cars);

    foreach (var car in existingCars)
    {
        //If there are no new cars then it had some and they have been removed
        if (newCars.Count() == 0)
        {
            missingCars.Add(car);
        }
        else
        {
            if (!newCarIds.Contains(car.CarId))
            {
                missingCars.Add(car);
            }
        }
    }

    return missingCars;
}

这可以按照我的意愿运行 - 但如果我想为其他DTO的客户或公寓实现相同的功能,我将复制粘贴代码,但只更改变量名称和DTO类型 - 是否更好可能使用泛型,这将保持算法和逻辑,但允许我在任何DTO上使用?

3 个答案:

答案 0 :(得分:5)

如果所有ID都是int类型,那么您可以通过传递Func来确定ID。

private List<T> BuildToDelete<T>(
    IList<T> newItems, 
    IList<T> existingItems, 
    Func<T, int> getId)
{
    var missingItems = new List<T>();

    var items = newItems.Select(getId);
    var newItemIds = new HashSet<int>(items);

    foreach (var item in existingItems)
    {
        if (newItems.Count() == 0)
        {
            missingItems.Add(item);
        }
        else
        {
            if (!newItemIds.Contains(getId(item)))     
            {
                missingItems.Add(item);
            }
        }
    }

    return missingItems;
}

然后拨打如下所示:

var results = BuildToDelete(newCars, existingCars, c => c.CarId);

答案 1 :(得分:3)

假设您使用了注释中提到的接口方法,通用版本可能如下所示:

private List<TEntity> BuildEntitiesToDelete(IList<TEntity> newEntities, IList<TEntity> existingEntities) where TEntity : IEntityWithId
{
    var missingEntities = new List<TEntity>();

    var entities = newEntities.Select(e => e.Id);
    var newEntityIds = new HashSet<int>(entities);

    foreach (var entity in existingEntities)
    {
        if (entities.Count() == 0)
        {
            missingEntities.Add(entity);
        }
        else
        {
            if (!newEntityIds.Contains(entity.Id))
            {
                missingEntities.Add(entity);
            }
        }
    }

    return missingEntities;
}

IEntityWithId可能是界面的一个糟糕名称,但我会留下更好的名称。

答案 2 :(得分:0)

尝试更清洁的东西:

1)创建灵活的相等比较器(需要添加一些空检查等)。

public class FuncEqualityComparer<T> : IEqualityComparer<T>
{
    Func<T, T, bool> comparer;
    Func<T, int> hash;

    public FuncEqualityComparer (Func<T, T, bool> comparer, Func<T, int> hash)
    {
        this.comparer = comparer;
        this.hash = hash;
    }

    public bool Equals (T x, T y) => comparer (x, y);

    public int GetHashCode (T obj) => hash (obj);
}

2)现在,只是简单地说:

var carComparerByID = new FuncEqualityComparer<CarDTO> ((a, b) => a.CarId == b.CarId, x => x.CarId.GetHashCode ());

var result = existingCars.Except (newCars, carComparerByID).ToList ();