2012-04-03 52 views
0

我需要允許我的內容管道擴展使用類似於工廠的模式。我開始一個字典類型:從XNA內容管道擴展中訪問服務

public delegate T Mapper<T>(MapFactory<T> mf, XElement d); 

public class MapFactory<T> 
{ 
    Dictionary<string, Mapper<T>> map = new Dictionary<string, Mapper<T>>(); 

    public void Add(string s, Mapper<T> m) 
    { 
     map.Add(s, m); 
    } 

    public T Get(XElement xe) 
    { 
     if (xe == null) throw new ArgumentNullException(
      "Invalid document"); 
     var key = xe.Name.ToString(); 
     if (!map.ContainsKey(key)) throw new ArgumentException(
      key + " is not a valid key."); 
     return map[key](this, xe); 
    } 

    public IEnumerable<T> GetAll(XElement xe) 
    { 
     if (xe == null) throw new ArgumentNullException(
      "Invalid document"); 
     foreach (var e in xe.Elements()) 
     { 
      var val = e.Name.ToString(); 
      if (map.ContainsKey(val)) 
       yield return map[val](this, e); 
     } 
    } 
} 

這是一個類型的對象,我想存儲:

public partial class TestContent 
{ 
    // Test type 
    public string title; 

    // Once test if true 
    public bool once; 

    // Parameters 
    public Dictionary<string, object> args; 

    public TestContent() 
    { 
     title = string.Empty; 
     args = new Dictionary<string, object>(); 
    } 

    public TestContent(XElement xe) 
    { 
     title = xe.Name.ToString(); 
     args = new Dictionary<string, object>(); 
     xe.ParseAttribute("once", once); 
    } 
} 

XElement.ParseAttribute是一個擴展方法,它的工作原理正如人們所預料。它返回一個布爾值,如果成功則返回true。

問題是我有許多不同類型的測試,每種測試都以特定測試所特有的方式填充對象。元素名稱是MapFactory字典的關鍵。這種類型的測試儘管非典型,但卻說明了我的問題。

public class LogicTest : TestBase 
{ 
    string opkey; 
    List<TestBase> items; 

    public override bool Test(BehaviorArgs args) 
    { 
     if (items == null) return false; 
     if (items.Count == 0) return false; 
     bool result = items[0].Test(args); 
     for (int i = 1; i < items.Count; i++) 
     { 
      bool other = items[i].Test(args); 
      switch (opkey) 
      { 
       case "And": 
        result &= other; 
        if (!result) return false; 
        break; 
       case "Or": 
        result |= other; 
        if (result) return true; 
        break; 
       case "Xor": 
        result ^= other; 
        break; 
       case "Nand": 
        result = !(result & other); 
        break; 
       case "Nor": 
        result = !(result | other); 
        break; 
       default: 
        result = false; 
        break; 
      } 
     } 
     return result; 
    } 

    public static TestContent Build(MapFactory<TestContent> mf, XElement xe) 
    { 
     var result = new TestContent(xe); 
     string key = "Or"; 
     xe.GetAttribute("op", key); 
     result.args.Add("key", key); 
     var names = mf.GetAll(xe).ToList(); 
     if (names.Count() < 2) throw new ArgumentException(
       "LogicTest requires at least two entries."); 
     result.args.Add("items", names); 
     return result; 
    } 
} 

我實際的代碼是更復雜的工廠有兩本字典,一個一個輪流到的XElement的內容類型編寫和另一所使用的閱讀器創建實際的遊戲對象。

我需要在代碼中構建這些工廠,因爲它們將字符串映射到委託。我有一個包含這些工廠的服務。任務是使這些工廠類可用於內容處理器。無論處理器本身還是它用作參數的上下文都沒有任何已知的掛鉤來連接IServiceProvider或等價物。

任何想法?

回答

0

我需要基本上按需創建數據結構,而不必訪問基礎類,因爲它們來自第三方,在這種情況下是XNA Game Studio。只有一種方法可以做到這一點,我知道......靜態地。

public class TestMap : Dictionary<string, string> 
{ 
    private static readonly TestMap map = new TestMap(); 

    private TestMap() 
    { 
     Add("Logic", "LogicProcessor"); 
     Add("Sequence", "SequenceProcessor"); 
     Add("Key", "KeyProcessor"); 
     Add("KeyVector", "KeyVectorProcessor"); 
     Add("Mouse", "MouseProcessor"); 
     Add("Pad", "PadProcessor"); 
     Add("PadVector", "PadVectorProcessor"); 
    } 

    public static TestMap Map 
    { 
     get { return map; } 
    } 

    public IEnumerable<TestContent> Collect(XElement xe, ContentProcessorContext cpc) 
    { 
     foreach(var e in xe.Elements().Where(e => ContainsKey(e.Name.ToString()))) 
     { 
      yield return cpc.Convert<XElement, TestContent>(
       e, this[e.Name.ToString()]); 
     } 
    } 
} 

我把這個更進一步,創建的內容的處理器對每種類型的TestBase:

/// <summary> 
/// Turns an imported XElement into a TestContent used for a LogicTest 
/// </summary> 
[ContentProcessor(DisplayName = "LogicProcessor")] 
public class LogicProcessor : ContentProcessor<XElement, TestContent> 
{ 
    public override TestContent Process(XElement input, ContentProcessorContext context) 
    { 
     var result = new TestContent(input); 
     string key = "Or"; 
     input.GetAttribute("op", key); 
     result.args.Add("key", key); 
     var items = TestMap.Map.Collect(input, context); 
     if (items.Count() < 2) throw new ArgumentNullException(
       "LogicProcessor requires at least two items."); 
     result.args.Add("items", items); 
     return result; 
    } 
} 

任何試圖引用或訪問類如調用TestMap.Collect將產生下面的靜態類如果需要的話。我基本上將代碼從LogicTest.Build移到處理器。我也在處理器中執行任何需要的驗證。

當我開始閱讀這些課程的時候,我會給ContentService提供幫助。