2014-05-21 42 views
2

我正在嘗試爲lisp風格的plist創建一個抽象語法。例如:面向對象的嵌套字典數據結構

(:A 1 :B (:X 3 :Y 2) :C 4) 

這裏的語法到目前爲止(在EBNF):

Plist -> { Key Value }* 
Key -> string 
Value -> string | Plist 

我要代表在C#中這個數據結構。不幸的是,我正在努力爲非終端創建類。在python這樣的動態類型語言中,這似乎很微不足道(字典值爲字符串或字典的字典)。但是在C#中,數據結構的用戶如何以多態的方式知道值是一個plist還是一個字符串?

這裏的C#代碼,我到目前爲止有:

interface Value { } 

class PList : Value 
{ 
    private Dictionary<string, Value> Dict; 

    public Value this[string key] 
    { 
     get 
     { 
      return Dict[key]; 
     } 
    } 
} 

class String : Value 
{ 
    public string Datum { get; set; } 
} 
+0

如果您使用對象代替值,您可以添加一個新的對象[] {#}或新的Dictionary作爲對象,那麼您可以使用遞歸方法來訪問和處理。 – Bit

回答

3

你肯定是在正確的軌道上。您嘗試使用的模式是Composite Pattern。在這種模式中,葉子和內部節點(在樹中和你的例子中)都使用常見的行爲或常見的抽象。然後抽象用於複合材料,像這樣:

public interface IValue 
{ 
    public void OperationOnValue(); 
    public List<IValue> GetChildren(); 
} 

public class CompositePList : IValue 
{ 
    private Dictionary<string, IValue> dict; 

    public void OperationOnValue() 
    { 
     foreach(var things in dict) 
     {}//things to do 
    } 

    public List<IValue> GetChildren() 
    { 
     return dict.Select(keyValue => keyValue.Value).ToList(); 
    } 
} 

public class StringValue : IValue 
{ 
    private string leafValue; 
    public void OperationOnValue() 
    {}//thing to do 

    public List<Children> GetChildren() 
    { 
     return null; //or return new List<Children>() 
    } 
} 

有了這個設計,你可以有一個根IValue,然後多態調用它OperationOnValue()。你有沒有更多的功能?

+0

複合模式當然有幫助。常見的抽象需要爲基本值返回一個字符串,但是爲嵌套值返回一個plist(類似於lisp的[getf](http://clhs.lisp.se/Body/f_getf.htm))。這似乎會導致該模式的問題。操作如何返回這些不同的類型? – ElliotPenson

+0

該模式的重點在於避免返回不同的東西。你只有'IValue's。換句話說,你的數據結構基本上是一個「IValue」根,然後你可以調用OperationOnValue()來做一個操作。如果你有另一種方法返回子IValue,你可以通過數據結構而不必檢查IValue的類型。請注意,即使在這種情況下,如果您想對葉節點(您所做的)做一些特殊的事情,您仍然需要檢查'IValue是否是StringValue'。 –

+0

@ElliotPenson我試了一下GetChildren()看​​我的編輯。 –