3

Imagine a method with the following signature:

public void ExampleMethod(string id, object data, 
                          ref object A, ref object B, ref object C)
{
  //...
}

The value in data needs to be assigned to either A, B, C or nothing, depending on the value of id. In short, if id == "A" then A = data;

The problem is that the body of this method is typed by a human but the signature is generated at runtime. Because of this, it is not possible to hard-code the logic because it is unknown at design-time how many ref parameters there will be and what they are called. This piece of code may be inserted into any number of methods, each potentially with a different signature, and it has to work in each and every one.

I know how to get all the parameters of the method one is currently in, but I can't figure out how to assign a value to one of these parameters. What I'm looking for is something like the following:

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;
    }
  }
}
David Rutten
  • 4,716
  • 6
  • 43
  • 72
  • Will the function signature be generated or is it fixed? – H H Feb 29 '12 at 09:43
  • 2
    It's not clear what you mean - why are you not in control of the method body? Why can you not just do the right thing in the method body? It sounds like it would *really* help if you could give more context here. (It's a pretty odd design, too, to be honest...) – Jon Skeet Feb 29 '12 at 09:44
  • @Henk, the signature is generated at runtime, so isn't known during designtime. I added some extra info to the post. – David Rutten Feb 29 '12 at 09:48
  • @Jon, I am in control of the method body. I'm not in control of the method signature. – David Rutten Feb 29 '12 at 09:49
  • @David but surely you can *detect* the signature, and write the method accordingly? The scenario is very unclear... – Marc Gravell Feb 29 '12 at 09:52
  • @DavidRutten: How can you write a method body without knowing the signature? Again, this seems like a *very* strange scenario which you should explain in more detail. – Jon Skeet Feb 29 '12 at 09:55
  • @Jon, people can write C# scripts in my application. I encase these scripts in a code-generated class and compile them at runtime. The signature of the method that contains the script is auto-generated and depends on the specific context in which the script runs (see: http://tinyurl.com/7g9l94w). One of my users wants to write a script that is flexible enough to work in all imaginable cases, i.e. he wants to be able to add, remove and rename output parameters without having to change the script code. – David Rutten Feb 29 '12 at 11:17

1 Answers1

2

You can't access parameters by name, as you can't really use reflection on variables/parameters. You might have some options if this was IL, but not really in C#. My advice would be: change the API, maybe something involving either an array or (perhaps better) a dictionary. Consider:

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

Not sure if that helps... but what you are trying to do is not really reflection-friendly. The other option is to generate this method dynamically, either as a part of your build process, or via IL. Either should be fine. So it could essentially generate (as either C# or (at runtime) 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 */
    }
}

An additional approach: the typed object: say you have:

public void ExampleMethod(string id, object data, SomeType obj) {...}

where obj is an object with properties such as "A", "B", "C"; then what you are trying to generate is:

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

which can of course be done with reflection:

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

or if performance is critical, something like fast-member:

var wrapped = ObjectAccessor.Create(obj); 
wrapped[id] = data;
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Thanks Marc, but changing the API is not an option at this stage. The code is already out there and I cannot afford to distribute a breaking change. I was hoping parameters could be assigned similar to FieldInfo.SetValue... I guess not. – David Rutten Feb 29 '12 at 09:51
  • @DavidRutten indeed, they cannot – Marc Gravell Feb 29 '12 at 09:57
  • @DavidRutten if you can be clearer on the context, I might be able to help some more; for example, if this is an abstract method or an interface method, and you need to produce the concrete implementation, then that could be done with meta-programming without too much pain – Marc Gravell Feb 29 '12 at 10:03
  • this code will end up in a Script object within a visual programming language (see image: http://tinyurl.com/7g9l94w ). The grey lines in the code editor are generated and depend on the layout of the component. It's quite a complex case obviously, but there are other approaches we can take as it seems this whole ParameterInfo thing won't work. – David Rutten Feb 29 '12 at 10:22