2010-11-03 45 views
3

我需要投一個Action<string>Action<object>。雖然這是一般的類型不安全,但在我的情況下,它總是會被一個字符串調用。我得到這個錯誤:鑄造動作<string>至行動<object>

Unable to cast object of type 'System.Action1[System.String]' to type 'System.Action 1 [System.Object]'。

任何線索?反思是公平的遊戲。將一個代表包裝到另一個代表不是

更新: 我創建了一個新的問題,在Creating an performant open delegate for an property setter or getter與我的問題的一個更好的解釋,並用包裝,我想提高

+3

對不起,但CLR只是沒有辦法做到這一點,沒有包裝一個委託與另一個。 – Gabe 2010-11-03 04:59:29

+0

這可能是有幫助的,包括爲什麼你試圖做到這一點(與第三方圖書館,好奇心等工作),因爲如Gabe提到,這是不可能的,沒有包裝在另一個代表。然而,有可能解決您可能遇到的根本問題。 – 2010-11-03 05:10:53

+0

任何特殊的原因反對包裹代表與其他..它的非常直接的反思... – RameshVel 2010-11-03 06:08:54

回答

1

我知道你的文章指定包裝在另一個代表不是一個選項,但不幸的是,這真的是你最好的選擇。 CLR根本不允許在這個方向上的代表之間進行演員表演。沒有任何反射可以解決這個問題。你能否進一步闡述爲什麼這不是一種選擇?

之所以會產生類型安全問題,是因爲調用者可以將任何對象傳入Action<object>Action<string>只能處理字符串。即使您的代碼只通過了string,CLR也不能保證這一點,因此不允許進行不安全的轉換。

我能想到的下一個最佳選擇是更改原始方法,該方法將Action<string>中包含的參數從string取爲object。然後讓它手動驗證類型是string。例如

// Original Version 
void Method(string str) { 
    // Operate on the string 
} 

// Modified version 
void Method(object obj) { 
    string str = (string)obj; 
    // operate on the string 
} 
6

首先解決,這不是安全的。可以接受任何字符串的東西不能(必然)接受任何對象。想想一個例子方法:

void method(String s) 
{ 
    s.Trim(); 
} 

顯然,如果s是一個對象而Trim這會失敗。

從技術上講,這意味着Action是T.逆變你可以指定一個Action<string>一個假設Action<SubclassString>參考,但string不能被繼承。

確實,C#允許普通的不安全轉換(例如object本身轉換爲string),風險爲InvalidCastException。但是,他們選擇不實施不安全的委託轉換的基礎設施。

編輯:我不知道沒有包裝的方式。

+0

當然。我對這個問題進行了澄清。我的合同確保它只能用字符串調用。所以鑄造的確是我需要的。 – 2010-11-03 04:46:44

+0

版主能否解答這個問題?它不會幫助我,也可能阻止其他人查看這個問題。 – 2010-11-03 04:51:07

+2

@David,當我回答這個問題時,它說:「我需要向'Action '投出一個動作',理由是它應該是可能的。」並且我解釋了爲什麼這是錯誤的。即使現在,問題的標題也不清楚。 – 2010-11-03 04:53:46

0

由於反射是公平的遊戲,我會建議如下。如果您跟蹤Object,MethodInfo以及可能執行的參數,則可以避開投射問題。這個概念是如何工作的一個例子如下:

Action<string> s; 
Action<object> o; 

object sTarget = s.Target; 
object oTarget = o.Target; 

MethodInfo sMethod = s.Method; 
MethodInfo oMethod = o.Method; 

// Time to invoke in a later time. 
sMethod.Invoke(sTarget, new object[] { strVal }); 
oMethod.Invoke(oTarget, new object[] { objVal }); 

與此唯一的危險是,錯誤的參數類型將防錯法來執行的可能性。你可能需要在這裏做一些簿記來防止這種情況。但是,就你而言,由於可以保證字符串將被傳遞(並且由於字符串總是一個對象),所以這應該總是成功的。

1

對不起,我今天想找個辦法做到這一點,偶然發現這篇文章。真的,我發現這樣做的唯一簡單方法是將Action<string>換成新的Action<object>。在我的情況下,我將我的動作放入並行字典中,然後按類型檢索它們。

實際上,我正在處理一個消息隊列,其中可以定義操作來處理具有特定類型輸入的消息。

ConcurrentDictionary<Type, Action<object>> _actions = new ConcurrentDictionary<Type, Action<object>>(); 
Action<string> actionStr = s => Console.WriteLine(s); 

var actionObj = new Action<object>(obj => { 
    var castObj = (V)Convert.ChangeType(obj, typeof(V)); actionStr(castObj); 
}); 

_actions.TryAdd(typeof(string), actionObj);