是否可以在没有反射和没有字典的情况下从F(类型)转换到F <t> </t>

时间:2009-12-10 07:40:01

标签: .net generics reflection reflection.emit

首先,一点介绍。

我必须履行职责:

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,这意味着它不必接收它的方法信息。那么有可能抛弃字典吗?

5 个答案:

答案 0 :(得分:1)

  

是否可以在没有反射且没有字典的情况下从F(类型)转换为F?

不,MakeGenericType是正确的方法。

你提到了一个奇特的功能来做到这一点;该奇特的功能仍然需要以call指令结束,这需要MethodInfoDelegate.CreateDelegate相同的方式。

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

答案 1 :(得分:0)

考虑到这一点,我的印象是,如果你想保持高效,你就不会摆脱字典。您可以通过发射IL(通过LGC,Reflection.Emit或Expression Tree)来消除反射Invoke,但是您仍然需要为每种类型创建一个存根。

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

答案 2 :(得分: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();

答案 3 :(得分: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
}

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

答案 4 :(得分:0)

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

相关问题