C# 在结构上调用内部方法

C# 在结构上调用内部方法,c#,reflection,xna,touch,cil,C#,Reflection,Xna,Touch,Cil,为了在XNA框架中填充一个锁定的数据类型,我采用了一种可怕的黑客手段:在一个结构中有一个内部方法,我希望在不向垃圾收集器提供数据的情况下调用它 如果我将所述结构装箱在对象变量中,并使用MethodInfo.Invoke(),则该调用本身将通过装箱参数为垃圾收集器提供信息: private object boxedTouchCollection; void test() { MethodInfo addTouchLocationMethod = typeof(TouchCollection)

为了在XNA框架中填充一个锁定的数据类型,我采用了一种可怕的黑客手段:在一个结构中有一个内部方法,我希望在不向垃圾收集器提供数据的情况下调用它

如果我将所述结构装箱在对象变量中,并使用
MethodInfo.Invoke()
,则该调用本身将通过装箱参数为垃圾收集器提供信息:

private object boxedTouchCollection;

void test() {
  MethodInfo addTouchLocationMethod = typeof(TouchCollection).GetMethod(
    "AddTouchLocation", BindingFlags.Instance | BindingFlags.NonPublic
  );
  addTouchLocationMethod.Invoke(
    this.boxedState, new object[] { /* parameters being boxed */ }
  );
}
我不确定这里是否可以使用
Delegate.CreateDelegate()
——我可以将第一个参数转换成一个对象,它将在装箱结构上工作吗?或者我可以存储未绑定的结构并将第一个参数声明为
ref TouchCollection

delegate void AddTouchLocationDelegate(
  ref TouchCollection collection,
  int id,
  // ...more parameters...
);

private TouchCollection touchCollection;

void test() {
  Delegate.CreateDelegate(
    typeof(AddTouchLocationDelegate),
    typeof(ref TouchCollection), // doesn't compile
    addTouchLocationMethod
  );
}
有什么方法可以让
委派.CreateDelegate()
工作吗? 还是我必须求助于动态IL生成?

这里有一种方法

它依赖于创建开放实例方法委托的
Delegate.CreateDelegate
。唯一棘手的是,您必须创建适当的委托类型才能通过引用传递结构

我认为不应该对这种技术进行任何装箱——无论是对方法的参数,还是对结构本身

示例:(对简化示例类型表示歉意)


这是另一个使用Linq表达式树的解决方案,我同时发现:

private delegate void AddTouchLocationDelegate(
  ref TouchCollection touchCollection,
  int id,
  TouchLocationState state,
  float x,
  float y,
  TouchLocationState prevState,
  float prevX,
  float prevY
);

private static AddTouchLocationDelegate createAddTouchLocationDelegate() {
  MethodInfo addTouchLocationMethod = typeof(TouchCollection).GetMethod(
    "AddTouchLocation", BindingFlags.Instance | BindingFlags.NonPublic
  );
  Type byrefTouchCollection = typeof(TouchCollection).MakeByRefType();

  ParameterExpression instance = Expression.Parameter(byrefTouchCollection, "instance");
  ParameterExpression idValue = Expression.Parameter(typeof(int), "id");
  ParameterExpression stateValue = Expression.Parameter(
    typeof(TouchLocationState), "state"
  );
  ParameterExpression xValue = Expression.Parameter(typeof(float), "x");
  ParameterExpression yValue = Expression.Parameter(typeof(float), "y");
  ParameterExpression prevStateValue = Expression.Parameter(
    typeof(TouchLocationState), "prevState"
  );
  ParameterExpression prevXValue = Expression.Parameter(typeof(float), "prevX");
  ParameterExpression prevYValue = Expression.Parameter(typeof(float), "prevY");

  Expression<AddTouchLocationDelegate> expression =
    Expression.Lambda<AddTouchLocationDelegate>(
      Expression.Call(
        instance, addTouchLocationMethod,
        idValue, stateValue, xValue, yValue, prevStateValue, prevXValue, prevYValue
      ),
      instance,
      idValue, stateValue, xValue, yValue, prevStateValue, prevXValue, prevYValue
    );

  return expression.Compile();
}

非常感谢你!我还没试过这个超负荷。工作很好,没有垃圾。
private delegate void AddTouchLocationDelegate(
  ref TouchCollection touchCollection,
  int id,
  TouchLocationState state,
  float x,
  float y,
  TouchLocationState prevState,
  float prevX,
  float prevY
);

private static AddTouchLocationDelegate createAddTouchLocationDelegate() {
  MethodInfo addTouchLocationMethod = typeof(TouchCollection).GetMethod(
    "AddTouchLocation", BindingFlags.Instance | BindingFlags.NonPublic
  );
  Type byrefTouchCollection = typeof(TouchCollection).MakeByRefType();

  ParameterExpression instance = Expression.Parameter(byrefTouchCollection, "instance");
  ParameterExpression idValue = Expression.Parameter(typeof(int), "id");
  ParameterExpression stateValue = Expression.Parameter(
    typeof(TouchLocationState), "state"
  );
  ParameterExpression xValue = Expression.Parameter(typeof(float), "x");
  ParameterExpression yValue = Expression.Parameter(typeof(float), "y");
  ParameterExpression prevStateValue = Expression.Parameter(
    typeof(TouchLocationState), "prevState"
  );
  ParameterExpression prevXValue = Expression.Parameter(typeof(float), "prevX");
  ParameterExpression prevYValue = Expression.Parameter(typeof(float), "prevY");

  Expression<AddTouchLocationDelegate> expression =
    Expression.Lambda<AddTouchLocationDelegate>(
      Expression.Call(
        instance, addTouchLocationMethod,
        idValue, stateValue, xValue, yValue, prevStateValue, prevXValue, prevYValue
      ),
      instance,
      idValue, stateValue, xValue, yValue, prevStateValue, prevXValue, prevYValue
    );

  return expression.Compile();
}
var d = createAddTouchLocationDelegate();
d(
  ref this.touches,
  1, TouchLocationState.Pressed, 10, 10, TouchLocationState.Released, 0, 0
);