给方法参数赋值

3

想象一个拥有以下签名的方法:

public void ExampleMethod(string id, object data, 
                          ref object A, ref object B, ref object C)
{
  //...
}
data中的值需要根据id的值被赋给ABC或无值。简而言之,如果id == "A",则A = data; 问题在于该方法的主体是由人类键入的,但签名是在运行时生成的。因此,不可能硬编码逻辑,因为在设计时不知道会有多少ref参数以及它们的名称。这段代码可以插入任意数量的方法中,每个方法都有不同的签名,而且必须在每个方法中工作。
我知道如何获取当前方法的所有参数,但我无法弄清如何将值赋给其中一个参数。我要找的是像以下示例一样的东西:
public void ExampleMethod(string id, object data, 
                          ref object A, ???????, ref object Z)
{
  MethodBase method = MethodBase.GetCurrentMethod();
  foreach (ParameterInfo parameter in method.GetParameters())
  { 
    if (id == parameter.Name)
    {
      // Problem: assign data to parameter.
      return;
    }
  }
}

2
不清楚你的意思——为什么你不能控制方法体呢?为什么你不能在方法体中做正确的事情呢?如果你能提供更多的上下文,那将会非常有帮助。(说实话,这个设计相当奇怪...) - Jon Skeet
@Henk,签名是在运行时生成的,因此在设计时未知。我在帖子中添加了一些额外信息。 - David Rutten
@Jon,我控制方法体。但是我无法控制方法签名。 - David Rutten
@David 但是你肯定可以检测签名,然后相应地编写方法吧?情境非常不清楚... - Marc Gravell
@DavidRutten:在不知道方法签名的情况下,你该怎么写方法体呢?再次强调,这似乎是一个非常奇怪的场景,你应该更详细地解释一下。 - Jon Skeet
显示剩余2条评论
1个回答

2

您不能通过名称访问参数,因为您无法在变量/参数上使用反射。如果这是IL,您可能有一些选项,但在C#中不是真正的。我的建议是:更改API,也许涉及数组或(更好的)字典。请考虑:

public void ExampleMethod(string id, object data,
        IDictionary<string,object> args) {
    args[id] = data;
}

我不确定这是否有所帮助...但你试图做的事情并不真正适合反射。另一个选项是动态生成此方法,可以作为构建过程的一部分或通过IL来完成。两种方式都可以。因此,它可以生成(作为C#或(在运行时)IL):

public void ExampleMethod(string id, object data, 
                          ref object A, ref object B, ref object C)
{
    switch(id) {
        case "A": A = data; break;
        case "B": B = data; break;
        case "C": C = data; break;
        default: /* do something */
    }
}

另一种方法:类型化对象。假设您有以下内容:
public void ExampleMethod(string id, object data, SomeType obj) {...}

如果obj是一个具有"A"、"B"、"C"等属性的对象,那么你尝试生成的内容应该如下:

switch(id) {
    case "A": obj.A = data; break;
    case "B": obj.B = data; break;
    case "C": obj.C = data; break;
    default: /* do something */
}

这当然可以通过反射来完成:

var prop = obj.GetType().GetProperty(id);
prop.SetValue(obj, data, null);

如果性能至关重要,可以使用像fast-member这样的库:

var wrapped = ObjectAccessor.Create(obj); 
wrapped[id] = data;

谢谢,马克,但是在这个阶段更改API不是一个选项。代码已经存在,我无法承担分发破坏性变化的成本。我希望参数可以像FieldInfo.SetValue一样赋值...我想不行。 - David Rutten
@DavidRutten 确实,它们无法。 - Marc Gravell
@DavidRutten如果您能更清楚地说明上下文,我可能能提供更多帮助;例如,如果这是一个抽象方法或接口方法,并且您需要生成具体实现,则可以使用元编程完成,而不会太痛苦。 - Marc Gravell
这段代码最终将出现在可视化编程语言中的脚本对象中(请参见图像:http://tinyurl.com/7g9l94w)。代码编辑器中的灰色线条是根据组件布局生成并依赖于其布局。显然这是一个相当复杂的情况,但我们可以采取其他方法,因为似乎这个ParameterInfo不起作用。 - David Rutten

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