如何使方法适用于不同对象的列表?

时间:2013-12-11 10:26:16

标签: c# visual-studio-2010 list object

我有几个不同类的列表,可能包含重复项。所以我需要一个方法,我可以传递这些列表来删除所有重复项(基于子属性id)并返回列表。对于特定的类对象,这没有问题,但对于不同类型(所有类型都具有属性id),这是如何实现的。

现在,我得到的是这个(这不起作用):

static class Product
{
    Guid id {get; set;}
    string name {get; set;}
    int price {get; set;}
}
static class Customer
{
    Guid id {get; set;}
    string firstname {get; set;}
    string lastname {get; set;}
}
class Program
{
    public void Controller()
    {
        List<Product> pl = GenerateList1();
        List<Customer> cl = GenerateList2();

        pl = Reduce(pl);
        cl = Reduce(cl);
    }
    private List<Product> GenerateList1()
    {
        //I know the filling of these is not correct but it should be enought for understandment
        List<Product> pl = new List<Product>();
        pl.Add(new Produkt("60c031f9-9a9b-4cd9-9e4c-3bde8f5e4665" "car", 2000);
        pl.Add(new Produkt("b786db8a-a55e-49aa-9a8d-c9c6f1c757c8" "pc", 500);
        pl.Add(new Produkt("b786db8a-a55e-49aa-9a8d-c9c6f1c757c8", "pc", 500);
    }
    private void GenerateList2()
    {
        List<Customer> cl = new List<Customer>();
        pl.Add(new Customer("176b628a-bc66-44b5-a842-ec81ef7fb0e0", "paul", "adam");
        pl.Add(new Customer("db439316-1d73-47b7-8462-f815966a6394" "frank", "smith");
        pl.Add(new Customer("176b628a-bc66-44b5-a842-ec81ef7fb0e0", "paul", "adam");
    }
    private List<object> Reduce(List<object> lo)
    {
        List<Guid> lg = new List<Guid>();
        List<object> lo2 = new List<object>();
        foreach(object o in lo)
        {
            if(!lg.Contains(o.id)
            {
                lg.Add(o.id);
                lo2.Add(o);
            }
        }
        return lo2;
    }
}

编辑:

这个有效的解决方案是在Adam Houldsworth的帮助下完成的:

    lv = Reduce(lv, v=>v.id);

    private static List<T> Reduce<T, TProp>(List<T> listTold, Func<T, TProp> getId)
    {
        List<Guid> lGuid = new List<Guid>();
        List<T> listTnew = new List<T>();
        foreach (T singleT in listTold)
        {
            if (!lGuid.Contains(Guid.Parse(getId(singleT).ToString())))
            {
                lGuid.Add(Guid.Parse(getId(singleT).ToString()));
                listTnew.Add(singleT);
            }
        }
        return listTnew;
    }

3 个答案:

答案 0 :(得分:3)

实现此目的的一种可能非常简单的方法是提供一种方法,该方法采用函数来检索要比较的项目。类似的东西:

private List<T> Reduce<T, TProp>(List<T> list, Func<T, TProp> getId)
{
}

我故意没有为Reduce提供实现,因为我无法编译Contains之类的依赖项,这些项通常需要实现接口的项目。

这将允许您提供不同的类并使用Func来概括ID的检索:

var customers = new List<Customer>();
customers = Reduce<Customer, Guid>(customers, c => c.CustomerId);

var products = new List<Product>();
products = Reduce<Product, int>(products, p => p.ProductId);

编译器中对类型推断的支持通常会让你逃脱:

customers = Reduce(customers, c => c.CustomerId);
products = Reduce(products, p => p.ProductId);

您可能必须使用TProp约束IEquatable或某些内容才能使其与Contains实施一起使用,但这是我首先要探索的路线:

private List<T> Reduce<T, TProp>(...) where TProp : IEquatable<TProp>

<小时/> 另一种方法是使用暴露ID的接口来概括类的功能。面对Func,如果我追溯更改,我现在倾向于偏离这条路线。

答案 1 :(得分:3)

您必须声明两个类都包含id属性:

interface IhasGUIDId
{
    Guid id {get; set;}
}

class Product : IhasGUIDId
{
    Guid id {get; set;}
    string name {get; set;}
    int price {get; set;}
}
class Customer : IhasGUIDId
{
    Guid id {get; set;}
    string firstname {get; set;}
    string lastname {get; set;}
}

然后您将能够比较特定界面的所有对象:

private List<IhasGUIDId> Reduce(List<IhasGUIDId> lo)
    {
        List<Guid> lg = new List<Guid>();
        List<IhasGUIDId> lo2 = new List<IhasGUIDId>();
        foreach(IhasGUIDIdo in lo)
        {
            if(!lg.contains(o.id)
            {
                lg.add(o.id);
                lo2.add(o);
            }
        }
        return lo2;
    }

答案 2 :(得分:0)

只需使用id属性定义一个接口,然后从中派生实体类:

public interface IHasID
{
    public Guid id {get; set;}
}

public class Product: IHasId
{
    Guid id {get; set;}
    string name {get; set;}
    int price {get; set;}
}
public class Customer: IHasId
{
    Guid id {get; set;}
    string firstname {get; set;}
    string lastname {get; set;}
}

然后你可以合并你的列表并迭代这个接口而不是具体的类:

public void Controller()
{
     List<Product> pl = GenerateList1();
     List<Customer> cl = GenerateList2();

     List<IHasId> = Reduce(p1, cl);
}
private List<IHasId> Reduce(List<IHasId> l1, List<IHasId> l2)
{
    List<Guid> lg = new List<Guid>();
    List<IHasId> l = l1.AddRange(l2).ToList();
    foreach(IHasId i in l)
    {
        if(!lg.contains(i.id)
        {
            lg.add(i.id);
            l.add(i);
        }
    }
    return l;
}