【问题标题】:In C# determining if an object o is an Action<...> or Func<....>在 C# 中确定对象 o 是 Action<...> 还是 Func<....>
【发布时间】:2011-12-12 22:42:18
【问题描述】:

假设你有一个 Dictionary 。它可能包含小数、字符串或其他有效类型。它还可以包含 Actions 和 Funcs,例如:

Action<string> or Action<int,int,string> etc.

是否有一种通用的方法可以发现给定的键 k 指向 Action 或 Func,然后调用相同的值?

var value = dict[key];
//some sort of predicate checking if value is invokeable

我考虑过使用 dynamic 关键字并简单地在结果对象上调用 Invoke( args ),但这似乎很慢而且不优雅。

【问题讨论】:

  • 在我看来,您的存储机制需要重新考虑,而不是缓慢的解决方法。

标签: c# reflection metaprogramming


【解决方案1】:

你可以测试它是一个委托:

Delegate d = value as Delegate;
if(d != null) d.DynamicInvoke(args);

但是!如果您不知道调用之前的签名,那么知道要提供什么参数(在对象数组中)会很棘手。

【讨论】:

  • Doh,它是大写的 D 代表。谢谢!
  • 是的,很难想象他会在不知道他的函数签名的情况下获得可用的 args,或者即使他有要调用的函数。
  • 我不确定这会比动态快得多。需要明确的是,Delegate.DynamicInvoke 回退到反射来调用委托。我希望它在效率方面与动态处于同一水平。动态缓存实际上可能更快。
  • @Dustin,但动态不会为您做任何静态分析。例如,d.Invoce(args) 可以编译得很好。使用 Marc 的解决方案,您不会遇到这个问题。
  • DynamicInvoke 也不做任何静态分析。它是 100% 后期绑定的,并将对象数组作为参数列表。
【解决方案2】:

如果您不想通过动态或 Delegate.DynamicInvoke 动态调用它,您可以使用一些通用扩展方法为您执行测试。

首先,将您的字典设为 Dictionary 而不是对象。

接下来,创建几个扩展方法(或更多以匹配您关心的委托类型)。

public static bool TryInvoke<T>(this Delegate del, T arg)
{
    var action = del as Action<T>;
    if (action != null)
    {
        action(arg);
        return true;
    }

    return false;
}

public static bool TryFunc<T, TResult>(this Delegate del, T arg, out TResult result)
{
    result = default(TResult);

    var func = del as Func<T, TResult>;
    if (func != null)
    {
        result = func(arg);
        return true;
    }

    return false;
}

最后,您可以像这样使用扩展方法...

var value = dict[key];

if (value.TryInvoke(20))
{
    // do something...
}
else
{
    int result;
    if (value.TryInvoke(20, out result))
    {
        // do something else...
    }
}

不难想象将其构建为一个小型库并重新使用它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-13
    • 1970-01-01
    • 1970-01-01
    • 2011-03-19
    • 2011-04-19
    • 1970-01-01
    相关资源
    最近更新 更多