我有几个不同类的列表,可能包含重复项。所以我需要一个方法,我可以传递这些列表来删除所有重复项(基于子属性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;
}
答案 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;
}