跟踪对象关系列表的最佳方法是什么?

时间:2013-11-29 11:55:32

标签: c# .net list

假设示例:我有一个客户列表和内存中的产品列表。我希望能够访问每个客户购买的产品以及购买特定产品的客户:

class Customer
{
    public List<Product> Products { get; set; }
}
class Product
{
    public List<Customer> CustomersWhoBoughtThis { get; set; }
}


var customers = new List<Customer>();
var products = new List<Product>();

//add the customers
var customer1 = new Customer();
customers.Add(customer1);
var customer2 = new Customer();
customers.Add(customer2);

//add the products
var product1 = new Product();
products.Add(product1);
var product2 = new Product();
products.Add(product2);

//add a purchased product for customer1
customer1.Products.Add(product1);

//How do I get customer1 from product1?
foreach (var customerWhoBoughtProduct1 in product1.CustomersWhoBoughtThis)
{
    //do something
}

我可以手动将客户添加到产品的CustomersWhoBoughtThis列表中,但我觉得这很容易出错,因为您可能忘记在某个地方执行此操作。

这有更好的实施吗?也许是某种处理功能的包装类,但我不确定它是如何实现的。有什么建议吗?

由于

6 个答案:

答案 0 :(得分:2)

您可以定义一些包装类,或者实现您自己的IList接口,然后您可以实现自己的事件支持通知。然而,使用内置的东西要简单得多。我会使用BindingList<T>,它有一个名为ListChanged的事件,它允许您获得一些通知,包括项目添加通知。请尝试以下代码:

class Customer {
  public Customer(){
    Products = new BindingList<Product>();
    Products.ListChanged += (s,e) => {
       if(e.ListChangedType == ListChangedType.ItemAdded){
         Products[e.NewIndex].CustomersWhoBoughtThis.Add(this);
       }
    };
  }
  public BindingList<Product> Products { get; set; }
}

答案 1 :(得分:2)

通常当我有一个循环关系时,我指定一个实体作为关系的“所有者”。所有者负责管理关系,因此该管理的任何代码都应该封装在其中。

在这种情况下,由于客户实际执行了操作(客户购买产品),因此最好是Customer类是关系所有者。

因此,Product类将是:

public class Product
{
  //other product properties

  //field for the customers list
  private List<Customer> customers = new List<Customer>();

  //read-only property for outside access
  public IEnumerable<Customer> Customers 
  {
    get { return customers; }
  }

  //internal method that will only be called by the customer class
  internal void AddCustomer(Customer customer)
  {
    customers.Add(customer);
  }

  //internal method that will only be called by the customer class
  internal void RemoveCustomer(Customer customer)
  {
    customers.Remove(customer);
  }
}

并且客户将是:

public class Customer
{
  //other customer properties

  //field for the product list
  private List<Product> products = new List<Product>();

  //read-only property for outside access
  public IEnumerable<Product> Products
  {
    get { return products; }
  }

  //public method, open to the world
  public void BuyProduct(Product product)
  {
    products.Add(product);
    product.AddCustomer(this);
  }

  //public method, open to the world
  public void RemoveProduct(Product product)
  {
    products.Remove(product);
    product.RemoveCustomer(this);
  }        
}

现在你这样做:

customer1.BuyProduct(product1);

并正确设置引用。此外,外部用户(来自其他程序集)将无法调用product1.AddCustomer

此外,值得注意的是,循环引用的序列化(对XML或JSON)是一个婊子,因为客户的产品的客户产品具有堆栈溢出异常。

答案 2 :(得分:1)

创建一个将执行两个操作的方法

void PairCustomerWithProduct(Customer customer, Product product)
{
    customer.Products.Add(product);
    product.CustomersWhoBoughtThis.Add(customer);
}

无论何时您需要将产品与客户配对,请调用此方法。

答案 3 :(得分:1)

我不会将List<T>公开为public,而是返回一个数组或序列。公开添加/删除产品的方法。

class Customer
{
    private List<Product> Products { get; set; }
    public void AddProduct(Product product)
    {
       Products.Add(product);
       if(!product.CustomersWhoBoughtThis.Contains(this))
           product.CustomersWhoBoughtThis.Add(this);
    }

    public void RemoveProduct(Product product)
    {
       Products.Remove(product);
       if(product.CustomersWhoBoughtThis.Contains(this))
           product.CustomersWhoBoughtThis.Remove(this);
    }

    public IEnumerable<Product> GetProducts()
    {
       return Products;
    }
}

答案 4 :(得分:0)

你可以这样试试,

Class Customer{listCustomer>} 

- 持有客户信息     类产品{list} - 保留产品信息

再添加一个类来维护组合

Class Sale{ public Customer, public Product }

获得SoldProducts列表的另一个类

Class SoldProduct{ list<Sale> }

答案 5 :(得分:0)

做一个关系课。

注意:我没有包含错误处理,只是基本的想法。另请注意,关系类(对于一对多关系)可以很容易地变为通用关系,并可以重用于任何类型的关系。我把它弄为具体,以使其更清晰。

class Customer
{
  public List<Products> Products 
  { 
     get { return CustomerProductRelationship.CustomerProducts[this];}
     set 
     {
        CustomerProductRelationship.AddPair(value, this);
     }
}

class Product
{
  public List<Products> Products 
  { 
     get { return CustomerProductRelationship.ProductCustomers[this];}
     set 
     {
        CustomerProductRelationship.AddPair(this, value);
     }
  }
}

static class CustomerProductRelationship
{
  public static Dictionary<Customer, List<Product>> CustomerProducts;
  public static Dictionary<Product, List<Customer> ProductCustomers;

  public static AddPair(Product product, Customer customer)
  {
       if (!CustomerProducts.Contains(customer))
          CustomerProducts.Add(customer, new List<Product>);

       CustomerProducts[customer].Add(product);

       if (!ProductCustomers.Contains(product))
          ProductCustomers.Add(product, new List<Customers>);

       CustomerProducts[product].Add(customer);
   }
}