2011-12-08 46 views
3

我想創建一個要在繪圖對象上執行的動作列表。這裏的非通用代碼將是什麼樣子:C#模式來緩存接受通用參數的動作

private Dictionary<String, Action<Drawing, String>> actions = new Dictionary<String, Action<Drawing, String>>(); 
private void LoadActions() 
{ 
    actions.Add("Height", (d, s) => d.Height = Double.Parse(s)); 
    actions.Add("Width", (d, s) => d.Width = Double.Parse(s)); 
} 
private void ProcessDrawing(Drawing drawing, String prop, String value) 
{ 
    actions[prop](drawing, value); 
} 

我的問題是,繪圖類是通用的一個(Drawing<T>),這樣因爲T沒有規定我不能這樣定義以下操作:

Dictionary<String, Action<Drawing<T>, String>> actions = new Dictionary<String, Action<Drawing<T>, String>>(); 

沒有緩存的代碼如下所示:

private void ProcessDrawing<T>(Drawing<T> drawing, String prop, String value) 
{ 
    var actions = new Dictionary<String, Action<Drawing<T>, String>>(); 
    actions.Add("Height", (d, s) => d.Height = Double.Parse(s)); 
    actions.Add("Width", (d, s) => d.Width = Double.Parse(s)); 
    actions[prop](drawing, value); 
} 

所以,我怎麼可以緩存一堆接受泛型類型參數的行動?

感謝,

回答

1

所有操作的基類是MulticastDelegate。您必須將字典定義爲Dictionary<String,MulticastDelegate>,並在從字典中檢索您的操作後使用適當的鑄件。

編輯: 測試表明,lambda表達式顯然不能被直接分配到MulticastDelegate類型的變量。這是因爲lambda表達式參數的類型是從分配給它的變量(或方法參數)的類型推斷出來的。因此,首先將其分配給具有正確Action<>類型的變量。然後將其分配給MulticastDelegate

在這個例子中,我將展示(通過方法參數,並通過可變)兩個版本:

public static void CallTestDelegate() 
{ 
    TestDelegate((d, s) => d.Height = Single.Parse(s)); 
} 

public static void TestDelegate(Action<RectangleF, string> action) 
{ 
    Dictionary<String, MulticastDelegate> dict = new Dictionary<string, MulticastDelegate>(); 
    dict.Add("a1", action); 
    Action<RectangleF, string> action2 = (d, s) => d.Width = Single.Parse(s); 
    dict.Add("a2", action2); 

    var a1 = (Action<RectangleF, string>)dict["a1"]; 
    a1(new RectangleF(), "15"); 
} 
+0

你能提供一個例子嗎?當我嘗試填充操作時出現以下錯誤:無法將lambda表達式轉換爲鍵入'System.MulticastDelegate',因爲它不是委託類型。我在執行操作檢查時也收到錯誤:actions.TryGetValue(prop,out action) – Manuel

+0

我添加了一個示例。我還測試過,如果匿名委託可以直接傳遞給'Add()'方法,與lambda不同。但這裏又出現了同樣的問題。 –

0

一種選擇是讓Drawing<T>從非通用接口IDrawingHeightWidth性質推導,然後改變你的行爲是Action<IDrawing,String>類型。

另一個選項(較少類型安全)是讓您的動作類型爲Action<dynamic,String>

+0

對象選項1需要太多的工作(如果可以完成的話),我用一個簡單的例子來說明我的目標是什麼。不能使用選項2,因爲代碼必須兼容3.5 – Manuel

+0

@Manuel:雖然它在回答問題時確實有助於瞭解問題的上下文。就.NET 3.5要求而言,我已經適當地編輯了標籤。 –

0

T是隻是一個佔位符,讓抽象類或接口代表要