无数据库实现90个C#产品间可变更关联关系的技术问询
Got it, let's walk through how to solve this problem with your existing C# DataContracts—no database required. Here's a practical, editable solution that handles dynamic product associations and their CO2 emission (ProductPoints) impacts.
1. Extend Your DataContracts to Track Associations
First, we need to add a way to store editable association relationships between products. Since associations are between individual products, we'll extend your Product class with a dictionary to map target product numbers to their association type. We'll also define an enum to clarify association types:
// Define clear association types public enum AssociationType { Positive, // Boosts CO2 value Negative, // Reduces CO2 value Neutral // No impact } [DataContract(Name = "Product", Namespace = "")] public class Product { private List<ProductTypes> productTypes = new List<ProductTypes>(); // Store associations: key = target ProductNumber, value = association type private Dictionary<long, AssociationType> productAssociations = new Dictionary<long, AssociationType>(); [DataMember(Name = "ProductName", IsRequired = true, Order = 1, EmitDefaultValue = false)] public string ProductName { get; set; } [DataMember(Name = "ProductTypes", IsRequired = true, Order = 2, EmitDefaultValue = false)] public List<ProductTypes> ProductTypes { get { return productTypes; } set { productTypes = value; } } // Serializeable association storage (preserves edits between sessions) [DataMember(Name = "ProductAssociations", IsRequired = false, Order = 3, EmitDefaultValue = false)] public Dictionary<long, AssociationType> ProductAssociations { get { return productAssociations; } set { productAssociations = value ?? new Dictionary<long, AssociationType>(); } } }
Note: I assumed ProductNumber is the unique identifier for each product (since it's a required field in ProductTypes). Adjust if you use a different unique key.
2. Define the CO2 Impact Logic
Next, let's formalize how associations affect ProductPoints, with guardrails to keep values within your 0-2 range:
Core Impact Rules
- Positive Association: When two products are selected together, each other's
ProductPointsincreases by 1 (capped at 2). - Negative Association: When two products are selected together, each other's
ProductPointsdecreases by 1 (floored at 0). - Neutral Association: No change to either product's value.
Implementation for Calculations
Create a static calculator class to handle point adjustments, especially when adding new products to the selected list:
public static class ProductImpactCalculator { // Calculate adjusted points for a single product based on selected peers public static int CalculateAdjustedPoints(Product targetProduct, List<Product> selectedProducts) { // Get the base CO2 value (adjust if a Product has multiple ProductTypes entries) int basePoints = targetProduct.ProductTypes.First().ProductPoints; int adjustedPoints = basePoints; foreach (var selectedProduct in selectedProducts) { var targetId = targetProduct.ProductTypes.First().ProductNumber; var selectedId = selectedProduct.ProductTypes.First().ProductNumber; // Skip the product itself if (targetId == selectedId) continue; // Apply association impact (default to neutral if no association exists) if (targetProduct.ProductAssociations.TryGetValue(selectedId, out var association)) adjustedPoints = ApplyAssociationEffect(adjustedPoints, association); else adjustedPoints = ApplyAssociationEffect(adjustedPoints, AssociationType.Neutral); } // Ensure value stays within 0-2 bounds return Math.Clamp(adjustedPoints, 0, 2); } // Apply single association effect private static int ApplyAssociationEffect(int currentPoints, AssociationType type) { return type switch { AssociationType.Positive => currentPoints + 1, AssociationType.Negative => currentPoints - 1, _ => currentPoints }; } // Batch-update all selected products' points (call this when adding a new product) public static void RefreshSelectedProductPoints(List<Product> selectedProducts) { // Calculate all new points first to avoid mid-update interference var pointUpdates = new Dictionary<long, int>(); foreach (var product in selectedProducts) { var productId = product.ProductTypes.First().ProductNumber; pointUpdates[productId] = CalculateAdjustedPoints(product, selectedProducts); } // Apply the updates foreach (var product in selectedProducts) { var productId = product.ProductTypes.First().ProductNumber; product.ProductTypes.First().ProductPoints = pointUpdates[productId]; } } }
3. Manage Editable Associations
To let users modify associations later, add a simple manager class to handle setting, removing, and checking relationships:
public static class AssociationManager { // Set a mutual association between two products (adjust to one-way if needed) public static void SetMutualAssociation(Product productA, Product productB, AssociationType type) { var idA = productA.ProductTypes.First().ProductNumber; var idB = productB.ProductTypes.First().ProductNumber; // Update A -> B association if (productA.ProductAssociations.ContainsKey(idB)) productA.ProductAssociations[idB] = type; else productA.ProductAssociations.Add(idB, type); // Update B -> A association (since impacts are mutual per your requirement) if (productB.ProductAssociations.ContainsKey(idA)) productB.ProductAssociations[idA] = type; else productB.ProductAssociations.Add(idA, type); } // Remove mutual association between two products public static void RemoveMutualAssociation(Product productA, Product productB) { var idA = productA.ProductTypes.First().ProductNumber; var idB = productB.ProductTypes.First().ProductNumber; productA.ProductAssociations.Remove(idB); productB.ProductAssociations.Remove(idA); } // Get the association type between two products public static AssociationType GetAssociation(Product productA, Product productB) { var idB = productB.ProductTypes.First().ProductNumber; return productA.ProductAssociations.TryGetValue(idB, out var type) ? type : AssociationType.Neutral; } }
Note: If you need one-way associations (e.g., Product A boosts Product B but not vice versa), remove the code that updates the reverse association.
4. Example Workflow
Here's how this all comes together when selecting products and modifying associations:
// Load your 90 serialized products List<Product> allProducts = LoadProductsFromXml(); // Your existing XML deserialization method List<Product> selectedProducts = new List<Product>(); // Step 1: Add first product var product1 = allProducts.First(p => p.ProductTypes.First().ProductNumber == 1); selectedProducts.Add(product1); // Step 2: Add second product and refresh points var product2 = allProducts.First(p => p.ProductTypes.First().ProductNumber == 2); selectedProducts.Add(product2); ProductImpactCalculator.RefreshSelectedProductPoints(selectedProducts); // Step 3: Modify their association and re-calculate AssociationManager.SetMutualAssociation(product1, product2, AssociationType.Negative); ProductImpactCalculator.RefreshSelectedProductPoints(selectedProducts); // Step 4: Save updated associations back to XML (preserves edits) SaveProductsToXml(allProducts); // Your existing XML serialization method
5. Serialization Notes
Since we used DataMember for the ProductAssociations dictionary, the DataContractSerializer will automatically serialize/deserialize these relationships. This means your edits will persist between sessions when you save/load the XML file.
内容的提问来源于stack exchange,提问作者J.Boehm

