c# - 在 Dictionary & ObservableCollection 中存储相同的对象实例
问题描述
我正在构建一个 WPF 应用程序。假设我们有一个超级市场;两种类型的对象称为Customer
和Product
。一个Customer
对象将Product
他拥有的 s 存储在他的购物车中。我有两个字典,我在其中存储我的Customer
&Product
对象的实例(两者都是唯一的)。
测试数据
客户名单( Dictionary<String,Customer>
) | 客户| | -------- | | 客户 A | | 客户 B |
产品列表( Dictionary<String,Product>
)
| 产品| | -------- | | 苹果 | | 香蕉 | | 西瓜| | 黄瓜|
客户A |
---|
苹果 |
香蕉 |
客户B |
---|
苹果 |
西瓜 |
我有一个我显示并用于修改我的 s(和他们的 s)ObservableCollection
CustomerList
的类型。我想实现以下内容:当我从中删除产品时,我希望它从'和'的“购物车”中消失。我在想的是,每个人都应该将产品存储为指向所需索引的指针(我已经做了一些 C++)。但是,当我在线阅读时,似乎指针在 C# 中是一个很大的禁忌。有没有容易做到这一点?当我删除或修改产品以使其“无法购买”时,我不想管理每个产品。Customer
Customer
Product
Apple
ProductList
CustomerA
CustomerB
Customer
ProductList
Customer
ProductList
编辑:添加了要求,我还希望能够修改 Productlist 中的 Apple 产品(例如将其重命名为 Red Apples)并让客户 A 和客户 B“购物车”也相应更改。
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace ConsoleApp1
{
public class Customer : INotifyPropertyChanged
{
private string name;
public ObservableCollection<Product> Items { get; set; }
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
public Customer(string _name)
{
name = _name;
Items = new ObservableCollection<Product>();
}
public void AddItem(Product item)
{
Items.Add(item);
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyRaised(string propertyname)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
}
}
}
public class Product : INotifyPropertyChanged
{
private string name;
private Guid guid;
private double price;
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
public Guid GUID
{
get
{
return guid;
}
set
{
guid = value;
}
}
public double Price
{
get
{
return price;
}
set
{
price = value;
}
}
public Product(string _name, double _price)
{
name = _name;
price = _price;
guid = Guid.NewGuid();
}
public void Modify(string _newname,double _price)
{
name = _newname;
price = _price;
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyRaised(string propertyname)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
}
}
}
public class MarketServices
{
// This will hold all my unique instances of Customer objects
public Dictionary<String, Customer> CustomerObjectsMainList_Services = new Dictionary<String, Customer>();
// This will hold all my unique instances of Product objects
public Dictionary<String, Product> ProductObjectsMainList_Services = new Dictionary<String, Product>();
// This will be used to display customers in a listview/datagrid and do modifications on it
// I want the objects in this observable collection to be "linked" or "point" to the instances in CustomerObjectsMainList_Services
// Such that if I modify any customername for example it would be reflected here too
// Also changing any product name or removing any product from ProductObjectsMainList_Services should be reflect in the "cart" of all customers
// in CustomerObjectsMainList_Services and CustomerObjectsList_Services
public ObservableCollection<Customer> CustomerObjectsList_Services = new ObservableCollection<Customer>();
public MarketServices()
{
this.CreateCustomers();
//Here I want to fill CustomerObjectsList_Services with the instances of customers in CustomerObjectsMainList_Services
foreach (var kvp in CustomerObjectsMainList_Services)
CustomerObjectsList_Services.Add(kvp.Value);
//Now if I delete a product from the ProductObjectsMainList_Services, will it get reflected on the Customer objects?
}
public void CreateCustomers()
{
CustomerObjectsMainList_Services.Add("CustomerA", new Customer("CustomerA"));
CustomerObjectsMainList_Services.Add("CustomerB", new Customer("CustomerB"));
ProductObjectsMainList_Services.Add("Apple", new Product("Apple",10));
ProductObjectsMainList_Services.Add("Banana", new Product("Banana",15));
ProductObjectsMainList_Services.Add("Watermelon", new Product("Watermelon",20));
ProductObjectsMainList_Services.Add("Cucumber", new Product("Cucumber",25));
CustomerObjectsMainList_Services["CustomerA"].AddItem(ProductObjectsMainList_Services["Apple"]);
CustomerObjectsMainList_Services["CustomerA"].AddItem(ProductObjectsMainList_Services["Banana"]);
CustomerObjectsMainList_Services["CustomerB"].AddItem(ProductObjectsMainList_Services["Apple"]);
CustomerObjectsMainList_Services["CustomerB"].AddItem(ProductObjectsMainList_Services["Watermelon"]);
}
}
class Program
{
public static void PrintCustomer(Customer customer)
{
foreach (var x in customer.Items)
{
Console.WriteLine("{0} {1} {2}", x.Name, x.Price,x.GUID);
}
}
static void Main(string[] args)
{
MarketServices test = new MarketServices();
test.CustomerObjectsList_Services.Add(test.CustomerObjectsMainList_Services["CustomerA"]);
test.CustomerObjectsList_Services.Add(test.CustomerObjectsMainList_Services["CustomerB"]);
Console.WriteLine("Printing Customer A objects");
PrintCustomer(test.CustomerObjectsMainList_Services["CustomerA"]);
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("Printing Customer B objects");
PrintCustomer(test.CustomerObjectsMainList_Services["CustomerA"]);
Console.WriteLine();
Console.WriteLine();
test.ProductObjectsMainList_Services["Apple"].Modify("Peaches",5);
Console.WriteLine("Printing Customer A objects after changing Apples to Peaches");
PrintCustomer(test.CustomerObjectsList_Services[0]);
test.ProductObjectsMainList_Services["Peaches"] = null;
Console.WriteLine("Printing Customer A objects after removing Peaches");
PrintCustomer(test.CustomerObjectsList_Services[0]);
}
}
}
Edit2:提供修改后的代码;如果我修改任何产品名称或价格,上述方法有效。但是,我不确定如何从 ProductObjectsMainList_Services 中“删除”产品并将其从所有在“购物车”中拥有该产品的客户中删除。
解决方案
public class Product
{
public string Name { get; init; }
public double Price { get; init; }
public bool Available { get; set; } = true;
}
//thread safe collection of single instances of products (by name)
//gurantees one instance of product class for a given name
public static class ProductList
{
private static readonly ConcurrentDictionary<string, Product> allProducts
= new ConcurrentDictionary<string, Product>();
//creates product, or returns existing one if same one with name already exists
public static Product AddProduct(string name, double price)
{
return allProducts.GetOrAdd(name, new Product { Name = name, Price = price });
}
//Gives you the only instance of that product
public static Product GetProduct(string name) => allProducts[name];
}
Usage is simple. Call AddProduct
to create a new product. Thread-safe and will never store a second instance in the dictionary of all products.
Then use GetProduct
to get the only instance for that product name.
If you don't need thread safety you could use a Dictionary
instead of ConcurrentDictionary
.
Your edit makes this answer moot (which I can delete). This presumes products are singletons based on name.
If you wanted to change the price, or anything but the unique key (name), you can simply modify the class instance.
Or change AddProduct
to use ConcurrentDictionary.AddOrUdpate
to keep the same instance but modify it.
That said, this design goes out the window if you can't uniquely key on something (for the concurrent dictionary).
For example, renaming a product would be possible if there was a unique identifier (like product ID, etc...) that could be used for the dictionary key instead of name.
推荐阅读
- javascript - 当我调整浏览器大小时,页脚 div 与上面的 div 重叠。我做错了什么?
- java - 有没有办法在 Spring Boot 中禁用 InfluxDB?
- javascript - 在 JavaScript 中查找 2 个标记之间花费的时间
- wso2 - 使用 siddhi 在某个时间窗口内未发生事件时发送警报
- python - 赛车模拟器的 Numpy 问题:没有名为“numpy.core._multiarray_umath”的模块
- android - 在 MaterialAlertDialog 中对齐文本内容
- javascript - 在反应中使用本地数据操作 SWR 数据
- laravel - 连接到 Laravel 回显存在通道问题
- neo4j - 当 parallel = true 时,apoc.periodic.iterate 失败
- python - 当我需要一次输入时,Python 要求输入两次