这更适合于键值存储还是树?

时间:2010-03-18 06:32:26

标签: c#

我正在试图找出代表某些数据的最佳方式。它基本上遵循表单Manufacturer.Product.Attribute = Value。类似的东西:

Acme。*。MinimumPrice = 100
Acme.ProductA.MinimumPrice = 50
Acme.ProductB.MinimumPrice = 60
Acme.ProductC.DefaultColor =蓝色

因此除了产品A和B的情况外,所有Acme产品的最低价格是100。我想将这些数据存储在C#中并且具有GetValue(“Acme.ProductC.MinimumPrice”)返回100但GetValue的一些功能(“Acme.ProductA.MinimumPrice”)返回50。

我不确定如何最好地代表数据。有没有一种干净的方法来用C#编写代码?

编辑:我可能不太清楚。这是需要存储在文本文件中的配置数据,然后以某种方式解析并存储在内存中,以便像我给出的示例一样检索它。

4 个答案:

答案 0 :(得分:2)

完全按照以下方式编写文本文件:

Acme.*.MinimumPrice = 100
Acme.ProductA.MinimumPrice = 50
Acme.ProductB.MinimumPrice = 60
Acme.ProductC.DefaultColor = Blue

将其解析为路径/值对序列:

foreach (var pair in File.ReadAllLines(configFileName)
                         .Select(l => l.Split('='))
                         .Select(a => new { Path = a[0], Value = a[1] }))
{
    // do something with each pair.Path and pair.Value
}

现在,有两种可能的解释,你想要做什么。字符串Acme.*.MinimumPrice可能意味着对于没有特定覆盖的任何查找,例如Acme.Toadstool.MinimumPrice,我们会返回100 - 即使在任何地方都没有引用Toadstool的内容文件。或者它可能意味着如果文件中有100的其他特定提及,它应该只返回Toadstool

如果它是前者,你可以将整个地段存储在一个扁平的字典中,并且在查找时间时不断尝试不同的密钥变体,直到找到匹配的东西。

如果是后者,则需要构建路径结构中实际出现的所有名称的数据结构,以避免返回实际不存在的名称的值。这对我来说似乎更可靠。

因此,使用后一个选项,Acme.*.MinimumPrice实际上是在“将此MinimumPrice值添加到任何没有自己特定定义值的产品”。这意味着您基本上可以在分析时处理这些对以消除所有星号,将其扩展为相当于配置文件的完整版本:

Acme.ProductA.MinimumPrice = 50
Acme.ProductB.MinimumPrice = 60
Acme.ProductC.DefaultColor = Blue
Acme.ProductC.MinimumPrice = 100

关于这一点的好处是你只需要一个平面字典作为最终表示,你可以使用TryGetValue[]来查找。结果可能会更大,但这一切都取决于您的配置文件有多大。

可以更少地存储信息,但我会选择一些简单易用的东西,然后给它一个非常简单的API,以便以后可以重新实现它。真的证明是必要的。您可能会发现(取决于应用程序)使查找过程更加复杂。

答案 1 :(得分:0)

我不完全确定你在问什么,但听起来你也在说。

  

除了两种情况外,我需要一个为每个产品ID返回固定值100的函数:ProductA和ProductB

在这种情况下,您甚至不需要数据结构。一个简单的比较函数就可以了

int GetValue(string key) { 
  if ( key == "Acme.ProductA.MinimumPrice" ) { return 50; }
  else if (key == "Acme.ProductB.MinimumPrice") { return 60; }
  else { return 100; }
}

或者你本来可以问

  

我需要一个函数,如果已经定义了将返回一个值,如果它不是

,则需要返回100

在这种情况下,我会使用Dictionary<string,int>。例如

class DataBucket {
  private Dictionary<string,int> _priceMap = new Dictionary<string,int>();
  public DataBucket() {
    _priceMap["Acme.ProductA.MinimumPrice"] = 50;
    _priceMap["Acme.ProductB.MinimumPrice"] = 60;
  }   
  public int GetValue(string key) { 
    int price = 0;
    if ( !_priceMap.TryGetValue(key, out price)) {
      price = 100;
    }
    return price;
  }
}

答案 2 :(得分:0)

其中一种方法 - 您可以创建嵌套字典:Dictionary<string, Dictionary<string, Dictionary<string, object>>>。在您的代码中,您应该按点分割“Acme.ProductA.MinimumPrice”,并获取或设置与分割块对应的字典的值。

另一种方法是使用Linq2Xml:您可以使用Acme作为根节点创建XDocument,将产品创建为根的子项,并将属性实际存储为产品或子节点上的属性。我更喜欢第二种解决方案,但如果您有数千种产品,它会更慢。

答案 3 :(得分:0)

我会采用OOP方法。您解释它的方式是所有产品都由对象表示,这很好。这似乎很好地利用了多态性。

我希望所有产品都有一个ProductBase,其默认属性为

virtual MinimumPrice { get { return 100; } }

然后,您的特定产品(例如ProductA)将覆盖功能:

override MinimumPrice { get { return 50; } }
相关问题