我需要将Action<string>
投射到Action<object>
。虽然这通常是类型不安全的,但在我的情况下,它总是会被一个字符串调用。我收到了这个错误:
Unable to cast object of type 'System.Action
1[System.String]' to type 'System.Action
1[System.Object]'.
任何线索?反思是公平的游戏。将一个代表包装到另一个代表不是。
更新: 我在Creating an performant open delegate for an property setter or getter创建了一个新问题,更好地解释了我的问题,并使用了我希望改进的包装解决方案
答案 0 :(得分:6)
首先,它不安全。可以接受任何字符串的东西不能(必然)接受任何对象。想想一个示例方法:
void method(String s)
{
s.Trim();
}
显然,如果s是没有Trim
的对象,则会失败。
从技术上讲,这意味着Action
在T上是逆变的。您可以为假设的Action<string>
引用分配Action<SubclassString>
,但string
不能被子类化。
C#允许定期不安全的强制转换(例如object
本身为string
),但风险为InvalidCastException
。但是,他们选择不为不安全的委托演员实施基础设施。
编辑:如果没有包装,我不知道如何做到这一点。
答案 1 :(得分: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
}
答案 2 :(得分: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);
答案 3 :(得分:0)
由于反思是公平的游戏,我将建议如下。如果跟踪对象,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 });
唯一的危险是可能会对错误的方法执行错误的参数类型。您可能需要在此处进行一些簿记以防止这种情况发生。但是,在您的情况下,由于保证将传递字符串(并且由于字符串始终是对象),因此应该始终成功。