将 Action<T> 转换为 Action<object>。

31

我该如何在C#中将 Action<T> 转换为 Action<Object>


6
这个问题没有意义,你不能创建一个 Action<T>,你必须指定一个类型。 - Ben Robinson
1
猜测这是协变性/逆变性问题之一,否则答案只会是 Action<object> - Steven Sudit
2
除非T被限制为类,否则无法将开放性泛型类型转换为Object。在代码中,当T:class时,将Action<T>分配给Action<Object>是合法的。Steven,澄清一下,这可能不能通过协变来解决。 - Dykam
@Dykam:是的,我相信你是正确的。协变性对于值类型是不起作用的。 - Steven Sudit
抱歉,T 当然是一种通用类型。 - Magnus Gladh
@MagnusGladh - 他们的意思是,作为通用类型是不够的。该类型还必须具有确保它不是值类型的约束条件。例如:T : class - ToolmakerSteve
5个回答

69

以下是您所要求的示例(可以在最后一行添加类型检查,以正确处理无效转换异常,使其更加用户友好):

public Action<object> Convert<T>(Action<T> myActionT)
{
    if (myActionT == null) return null;
    else return new Action<object>(o => myActionT((T)o));
}

也许您可以提供更多关于任务的细节,因为现在看起来有些奇怪。

4
你的else语句是多余的。 - jperez
3
@jperez - 这是个人偏好的问题。我们中有些人更喜欢看 if.. else.. 结构,即使涉及到 return 语句。原因是:这将在视觉上将在同一级别(这里是下一级)的逻辑上处于相同级别的语句放置在一起。也就是说,两个前进路径都由 if 的“条件”选择;它们可以被视为从主要流程“向下一级”的两个不同路径。在我看来,你建议的风格和这里所做的风格同样有效。这是一种权衡,取决于编码者选择强调什么。 - ToolmakerSteve

1
你可以像这样添加通用参数
    Action<object> Function<T>(Action<T> act) where T : class
    {
        return (Action<object>)act;
    }

我已经尝试过了,它实际上并不起作用。 - Lyon
可能你忘记了 where T : class - Sameman

1

我假设你有类似这样的代码:

void Foo(Action<object> action) { }

Action<something> myaction;

我想将我的操作转换为可以传递给Foo的形式。

但这样行不通。

Foo可以将任何类型派生自object的对象传递给该操作。但是,myaction只接受从某些东西派生的对象。


0
今天我在寻找一种方法来做这件事情,然后偶然发现了这篇文章。实际上,我发现唯一简单的方法是将 Action<string> 包装在一个新的 Action<object> 中。在我的情况下,我将我的 Actions 推入 Concurrent Dictionary 中,然后按类型检索它们。有效地说,我正在处理一个消息队列,其中可以定义处理具有特定输入类型的消息的操作。
var _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);

1
那是一个非常棒的解决方案!我也在类似你的情况下使用它。 - user585968
我之前也遇到了一个非常类似的问题,后来发现有一个更简单的解决方案。不要将 Action<specific> 转换为 Action<object>,而是将 Action<specific> 存储为对象,并在调用时将其强制转换回 Action<specific>。这种方法可行,因为关键在于类型,所以当你将其放入时,你知道它是正确的类型。 - Tyler W

0

不太确定您所说的转换意思是什么... Action 是一个通用的声明,指的是操作委托... 如果您想要一个可以针对 'object' 工作的操作委托,您可以这样做:

var myAction = new Action<object>(obj=> ... );

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接