3

首先,稍微介绍一下。

我必须发挥作用:

static class C
{
  static void F1(Type type)
  {
    // Do something to invoke F2<T>
  }
  static void F2<T>()
  {
    // bla bla bla
  }
}

我希望调用F1(Type),它又应该转换到与给定类型参数相关的泛型上下文并调用泛型对应项F2<T>

一个简单的实现将是一个简单的反射,就像这样(为了清楚起见,我省略了绑定标志):

void F1(Type type)
{
  var f2MethodInfo = typeof(C).GetMethod("F2").MakeGenericMethod(type);
  f2MethodInfo.Invoke(null, new object[0]);
}

一个更高级的实现将存储 F2 的打开方法信息 -typeof(C).GetMethod("F2")除了,但它仍然基本上是同一件事。

如果F1被多次调用并且我们希望提高性能,那么“市场上”的标准解决方案采用字典和Delegate.CreateDelegate方法,如下所示:

IDictionary<Type, Action> m_cache = new Dictionary<Type, Action>();
MethodInfo F2MethodInfo = typeof(C).GetMethod("F2");
void F1(Type type)
{
  Action action;
  if (!m_cache.TryGetValue(type, out action))
  {
    m_cache[type] = action = (Action)Delegate.CreateDelegate(typeof(Action), F2MethodInfo.MakeGenericMethod(type));
  }
  action();
}

现在回答我的问题。是否有可能完全消除字典?

例如,通过使用 Reflection.Emit 发出一些奇特的函数,该函数将接收 Type 实例和 F2MethodInfo 并在没有和字典的情况下进行内部转换?这个奇特的函数应该只发出一次并且适用于任何给定的类型。我想知道是否可以通过这种方式消除任何类型的缓存映射类型到委托。

谢谢。

编辑

为了讨论方便,让我们假设花哨的发出函数知道它应该调用 F2,这意味着它不必接收其方法信息。那么有可能放弃字典吗?

4

5 回答 5

1

是否可以在没有反射和没有字典的情况下从 F(Type) 转换到 F?

不,MakeGenericType是正确的做法。

你提到发出一个花哨的功能来做到这一点;那个花哨的功能仍然需要以call指令结束,并且需要以MethodInfo相同的方式Delegate.CreateDelegate执行。

您可以为一组已知类型预先生成代码,可能使用 Reflection.Emit 或 CodeDom,甚至是编译时代码生成。但我想如果你事先知道类型,你已经在你的字典方法中利用了它,对吧?

于 2009-12-10T07:57:49.903 回答
0

反方向做:

static void F1(Type type) {
    // do stuff
}

static void F2<T>() {
    F1(typeof(T))
}

不要胡说八道,这实际上是相同的上下文,除非您有没有告诉我们的进一步要求。

Java 的系统在这方面工作得更好:

static <T> void F1(Class<T> clazz) {
    // do stuff
}

您同时拥有通用上下文和类型对象。

于 2009-12-10T15:21:32.253 回答
0

想想看,我的印象是,如果你想保持效率,你就不会摆脱字典。您可以通过发出 IL(通过 LGC、Reflection.Emit 或 Expression Tree)来摆脱反射 Invoke,但您仍然必须为要使用的每种类型创建一个存根。

我想我会选择 LCG 并将这些代表存储在字典中。

于 2009-12-10T08:17:26.003 回答
0

当它被多次调用时,不要多次调用 F(Type),而是将其更改为将返回 Action 类型委托的工厂。

现在你可以用它做任何你喜欢的事情。

readonly IDictionary<Type, Action> _BlablasByType = new Dictionary<Type, Action>();
readonly MethodInfo _F2MethodInfo = typeof(C).GetMethod("F2");
void GetBlablaFor(Type type)
{
  Action action;
  if (! _BlablasByType.TryGetValue(type, out action))
  {
    _BlablasByType.Add(type, 
                       action = (Action)Delegate.CreateDelegate(typeof(Action),                                                                                                                                        
                                                                _F2MethodInfo.MakeGenericMethod(type));
  }
  return action;
}

var blabla = GetBlablaFor(typeof(Abc));
for(int i = 0; i < 10000; i++)
  blabla();
于 2009-12-10T09:20:17.163 回答
0

你不能。可以准备委托/接口以将其作为策略包含在您的设计中,并仅在初始化时保留反射。

于 2014-12-30T14:30:03.153 回答